﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Linq;
using UMC.Web;
using UMC.Net;
using System.Text.RegularExpressions;
using System.Text;
using System.Security.Cryptography;
using System.Collections.Specialized;
using System.IO.Compression;
using Microsoft.VisualBasic;

namespace UMC.ITME
{

    public class HttpProxy
    {
        public HttpProxy(SiteConfig site, UMC.Net.NetContext context, int staticModel, string rawUrl, string pfxDomain)
        {
            this.Site = site;
            this.IsLog = site.Site.IsDebug == true;


            this.Loger = new StringWriter();

            this.Context = context;
            this.User = context.Token.Identity();

            this.RawUrl = rawUrl;
            var searchIndex = rawUrl.IndexOf('?');
            this.Path = searchIndex > 0 ? rawUrl.Substring(0, searchIndex) : rawUrl;

            this.StaticModel = staticModel;

            this.Authority = this.Context.Url.Authority;


            if (site.Domains.Length > 0)
            {
                this.Domain = WeightUri(pfxDomain);
            }

            if (this.StaticModel == 0 || User.IsAuthenticated == false)
            {
                this.SiteCookie = new Entities.Cookie { Domain = Site.Root, user_id = context.Token.UserId.Value, IndexValue = 0 };

                InitClientCookie();
            }
            else if (User.IsAuthenticated)
            {
                var deviceIndex = UMC.Data.Utility.IntParse(context.Cookies[DeviceIndex], 0);
                if (deviceIndex == 0)
                {
                    this.SiteCookie = DataFactory.Instance().Cookie(_RootKey, User.Id.Value, deviceIndex) ?? new Entities.Cookie { Domain = Site.Root, user_id = context.Token.UserId.Value, IndexValue = 0 };
                    if ((this.SiteCookie.LoginTime ?? 0) < context.Token.LoginTime)
                    {

                        ClearCookie(pfxDomain);
                        DataFactory.Instance().Put(new Entities.Cookie
                        {
                            Domain = _RootKey,
                            user_id = User.Id.Value,
                            IndexValue = 0,
                            LoginTime = Utility.TimeSpan()
                        });
                    }
                    else
                    {
                        InitClientCookie();
                    }
                }
                else
                {
                    this.SiteCookie = DataFactory.Instance().Cookie(_RootKey, User.Id.Value, deviceIndex) ?? DataFactory.Instance().Cookie(_RootKey, User.Id.Value, 0) ?? new Entities.Cookie { Domain = Site.Root, user_id = context.Token.UserId.Value, IndexValue = 0 };
                    InitClientCookie();
                }

            }

            if (site.Test.Length > 0 && User.IsAuthenticated)
            {
                var authManager = UMC.Security.AuthManager.Instance();
                for (var i = 0; i < site.Test.Length; i++)
                {
                    var tUrl = site.Test[i];
                    if (tUrl.Users.Contains(User.Name))
                    {
                        this.Domain = new Uri(tUrl.Url);
                        this.IsTest = true;
                        break;
                    }
                    else if (tUrl.Auths.Length > 0)
                    {
                        if (authManager.Check(this.User, 0, tUrl.Auths).Any(r => r.Item1 == 1))
                        {
                            this.IsTest = true;
                            this.Domain = new Uri(tUrl.Url);
                            break;

                        }
                    }
                }
            }


            this.RawUrl = ReplaceRawUrl(this.RawUrl);

            this.StartTime = UMC.Data.Reflection.TimeSpanMilli(DateTime.Now);
        }
        private HttpProxy(HttpProxy proxy, SiteConfig siteConfig)
        {
            var user = siteConfig.Site.Account;

            this.Site = siteConfig;
            this.Loger = proxy.Loger;
            this.IsLog = proxy.IsLog;
            this.Password = UMC.Data.DataFactory.Instance().Password(SiteConfig.MD5Key(siteConfig.Root, user));

            this.SiteCookie = new Entities.Cookie
            {
                Account = user,
                user_id = UMC.Data.Utility.Guid(user, true),
                Domain = this.Site.Root,
                IndexValue = 0
            };
            this.IsChangeUser = false;
            this.Context = proxy.Context;
            this.Domain = new Uri(siteConfig.Domains[0]);
            this.RawUrl = proxy.RawUrl;
            this.Host = proxy.Host;
            this.User = proxy.User;

            this.Authority = proxy.Authority;
        }
        public Uri Domain
        {
            get;
            private set;
        }
        public SiteConfig Site
        {
            get;
            private set;
        }
        public UMC.ITME.Entities.Cookie SiteCookie
        {
            get;
            private set;
        }
        public System.IO.StringWriter Loger
        {

            get;
            private set;
        }
        public String Host
        {
            get;
            private set;
        }
        public bool? IsChangeUser
        {
            get;
            set;
        }
        String sourceUP;

        public string Password
        {
            get;
            private set;
        }
        const string DeviceIndex = "DeviceIndex";


        public static int WeightUri(SiteConfig site, Net.NetContext context)
        {
            if (site.WeightTotal > 0)
            {
                var value = 0;
                if (site.WeightTotal > 1)
                {
                    switch (site.Site.SLB ?? 0)
                    {
                        default:
                        case 0:
                            value = Random.Shared.Next(0, site.WeightTotal);
                            break;
                        case 1:
                            value = Math.Abs(Utility.Random(context.UserHostAddress) % site.WeightTotal);
                            break;
                        case 2:
                            var cookie = context.Cookies.Get(WebServlet.SessionCookieName) ?? context.Headers.Get("Cookie");
                            if (String.IsNullOrEmpty(cookie) == false)
                            {
                                value = Math.Abs(Utility.Random(cookie) % site.WeightTotal);
                            }
                            else
                            {
                                value = 0;
                            }
                            break;
                    }
                }

                var qty = 0;
                for (var i = 0; i < site.Weights.Length; i++)
                {
                    qty += site.Weights[i];
                    if (value < qty)
                    {
                        return i;
                    }
                }
            }
            return 0;
        }
        Uri WeightUri(string p)
        {
            Uri url;
            var d = this.Site.Domains[WeightUri(this.Site, this.Context)];
            var dIndex = d.IndexOf('*');
            if (dIndex > -1)
            {
                this.Host = d.Substring(dIndex + 1);

                if (String.IsNullOrEmpty(p))
                {
                    this.Context.Redirect(this.Context.Url.AbsoluteUri.Replace(this.Context.Url.Host, $"www-{this.Site.Root}{WebServlet.DomainUnion}{WebServlet.MainDomain}"));
                    throw new WebAbortException();
                }
                _RootKey = $"{this.Site.Root}_{p}";

                this.Authority = $"-{this.Site.Root}{WebServlet.DomainUnion}{WebServlet.MainDomain}";
                url = new Uri($"{d.Substring(0, dIndex)}{p}{this.Host}");
            }
            else
            {
                _RootKey = this.Site.Root;
                url = new Uri(d);
                if (String.IsNullOrEmpty(this.Site.Site.Host) == false)
                {
                    var host = this.Site.Site.Host;
                    if (String.Equals(host, "*"))
                    {
                        this.Host = this.Context.Url.Authority;
                    }
                    else
                    {
                        this.Host = host;
                    }
                }
                else
                {
                    this.Host = url.Host;
                }
            }
            return url;

        }
        private bool IsTest;
        UMC.Security.Identity _Account;
        public UMC.Security.Identity Account
        {
            get
            {
                if (_Account == null)
                {
                    var user = this.User;
                    if (String.IsNullOrEmpty(this.SiteCookie.Account))
                    {
                        _Account = UMC.Security.Identity.Create(user, UMC.Data.DataFactory.Instance().Roles(user.Id.Value, this.Site.Site.SiteKey.Value));

                    }
                    else if (String.Equals(this.SiteCookie.Account, user.Name))
                    {
                        var feildConfig = UMC.Data.JSON.Deserialize<Hashtable>(this.SiteCookie.Config);//?? new Hashtable();
                        if (feildConfig?.ContainsKey("__ROLE") == true)
                        {
                            _Account = UMC.Security.Identity.Create(user, (feildConfig["__ROLE"] as string ?? "").Split(','));
                        }
                        else
                        {
                            _Account = UMC.Security.Identity.Create(user, UMC.Data.DataFactory.Instance().Roles(user.Id.Value, this.Site.Site.SiteKey.Value));

                        }
                    }
                    else
                    {
                        var feildConfig = UMC.Data.JSON.Deserialize<Hashtable>(this.SiteCookie.Config) ?? new Hashtable();
                        var userName = this.SiteCookie.Account;
                        var alias = (feildConfig["__ALIAS"] as string) ?? userName;
                        _Account = UMC.Security.Identity.Create(UMC.Data.Utility.Guid(userName, true).Value, userName, alias, (feildConfig["__ROLE"] as string ?? "").Split(','), (feildConfig["__ORGA"] as string ?? "").Split(','));
                    }
                }
                return _Account;
            }
        }



        string Cookies = String.Empty;
        void InitClientCookie()
        {
            var sb = new StringBuilder();
            var ms = this.Context.Cookies;
            for (var i = 0; i < ms.Count; i++)
            {
                var name = ms.GetKey(i);
                var value = ms.Get(i);
                switch (name)
                {
                    case DeviceIndex:
                    case Web.WebServlet.SessionCookieName:
                        break;
                    default:
                        if (sb.Length > 0)
                        {
                            sb.Append("; ");
                        }
                        sb.Append(name);
                        sb.Append("=");
                        sb.Append(value);
                        break;
                }
            }
            this.Cookies = sb.ToString();
        }

        List<String> OuterCookies = new List<string>();
        public int StaticModel
        {
            get;
            private set;
        }

        public static int CheckStaticPage(SiteConfig config, string path)
        {
            foreach (var v in config.StatusPage)
            {

                if (path.StartsWith(v.StartPath) == false)
                {
                    continue;
                }

                if (path.EndsWith(v.EndPath) == false)
                {
                    continue;
                }
                return v.Value;
            }

            var vk = path;

            var v1 = path.LastIndexOf('.');
            if (v1 > -1)
            {
                vk = vk.Substring(v1).ToLower();

            }
            switch (vk)
            {
                case ".gif":
                case ".ico":
                case ".svg":
                case ".bmp":
                case ".png":
                case ".jpg":
                case ".jpeg":
                case ".css":
                case ".less":
                case ".sass":
                case ".scss":
                case ".js":
                case ".webp":
                case ".jsx":
                case ".coffee":
                case ".ts":
                case ".ttf":
                case ".woff":
                case ".woff2":
                case ".wasm":

                    return 0;
                default:
                    return -1;
            }

        }
        public string RawUrl
        {
            get;
            private set;
        }
        public string Path
        {
            get;
            private set;
        }
        public UMC.Net.NetContext Context
        {
            get;
            private set;
        }
        void SignOutHtml()
        {

            var sb = new StringWriter();
            sb.WriteLine("<div  class=\"umc-proxy-acounts\">");
            sb.WriteLine("<a class=\"home\" href=\"/UMC.TOP\">回到云桌面</a>");
            sb.WriteLine("<a class=\"signout\" href=\"/UMC.SignOut\">关闭登录</a>");
            sb.WriteLine("<a class=\"login\" href=\"/UMC.Login\">继续工作</a>");
            sb.WriteLine("</div>");
            sb.WriteLine($"<div style=\"color: #999; line-height: 50px; text-align: center;\">检测到您，正在退出{this.Site.Caption}!!!");
            sb.WriteLine("</div>");

            this.Context.AddHeader("Cache-Control", "no-store");
            this.Context.ContentType = "text/html; charset=UTF-8";

            using (System.IO.Stream stream = typeof(HttpProxy).Assembly
                                                  .GetManifestResourceStream("UMC.ITME.Resources.login-html.html"))
            {
                var str = new System.IO.StreamReader(stream).ReadToEnd();
                this.Context.Output.Write(new System.Text.RegularExpressions.Regex("\\{(?<key>\\w+)\\}").Replace(str, g =>
                {
                    var key = g.Groups["key"].Value.ToLower();
                    switch (key)
                    {

                        case "title":
                            return this.Site.Caption;
                        case "html":
                            return sb.ToString();
                    }
                    return "";

                }));

            }


        }
        void LoginCheckHtml()
        {

            var sb = new StringWriter();

            sb.WriteLine("<div style=\"margin-left: 50px;\" class=\"umc-proxy-acounts\">");
            sb.WriteLine("<a class=\"auto\" href=\"/UMC.Login/Auto\">免密自动绑定</a>");

            sb.WriteLine("<a class=\"input\" href=\"/UMC.Login/Input\">手输账户绑定</a>");

            sb.WriteLine("</div>");
            sb.WriteLine($"<div style=\"color: #999; line-height: 50px; text-align: center;\">推荐{this.Site.Caption}使用“免密自动绑定”，更简便。");
            sb.WriteLine("</div>");

            this.Context.AddHeader("Cache-Control", "no-store");
            this.Context.ContentType = "text/html; charset=UTF-8";

            using (System.IO.Stream stream = typeof(HttpProxy).Assembly
                                                  .GetManifestResourceStream("UMC.ITME.Resources.login-html.html"))
            {
                var str = new System.IO.StreamReader(stream).ReadToEnd();
                this.Context.Output.Write(new System.Text.RegularExpressions.Regex("\\{(?<key>\\w+)\\}").Replace(str, g =>
                {
                    var key = g.Groups["key"].Value.ToLower();
                    switch (key)
                    {

                        case "title":
                            return "请选择账户绑定方式";
                        case "html":
                            return sb.ToString();
                    }
                    return "";

                }));

            }

        }
        bool CheckAccountSelectHtml()
        {

            var scookies = DataFactory.Instance().Cookies(this.Site.Root, User.Id.Value).Where(r => String.IsNullOrEmpty(r.Account) == false).OrderBy(r => r.IndexValue).ToList();
            if (scookies.Count > 1)
            {
                var sb = new StringWriter();
                if (scookies.Count == 2)
                {
                    sb.WriteLine("<div style=\"margin-left: 50px;\" class=\"umc-proxy-acounts\">");
                }
                else
                {
                    sb.WriteLine("<div class=\"umc-proxy-acounts\">");
                }
                foreach (var sc in scookies)
                {
                    sb.WriteLine("<a href=\"/UMC.Login/{0}\">{1}</a>", sc.IndexValue ?? 0, sc.Account);

                }
                sb.WriteLine("</div>");

                this.Context.AddHeader("Cache-Control", "no-store");
                this.Context.ContentType = "text/html; charset=UTF-8";
                using (System.IO.Stream stream = typeof(HttpProxy).Assembly
                                                      .GetManifestResourceStream("UMC.ITME.Resources.login-html.html"))
                {
                    var str = new System.IO.StreamReader(stream).ReadToEnd();
                    this.Context.Output.Write(new System.Text.RegularExpressions.Regex("\\{(?<key>\\w+)\\}").Replace(str, g =>
                    {
                        var key = g.Groups["key"].Value.ToLower();
                        switch (key)
                        {
                            case "title":
                                return "您有多个账户，请选择";
                            case "html":
                                return sb.ToString();

                        }
                        return "";

                    }));

                }
                return true;
            }
            return false;

        }
        void LoginHtml(String error, bool isUser)
        {

            using (System.IO.Stream stream = typeof(HttpProxy).Assembly
                                                     .GetManifestResourceStream("UMC.ITME.Resources.login.html"))
            {
                this.Context.AddHeader("Cache-Control", "no-store");
                this.Context.ContentType = "text/html; charset=UTF-8";

                var str = new System.IO.StreamReader(stream).ReadToEnd();
                var v = new System.Text.RegularExpressions.Regex("\\{(?<key>\\w+)\\}").Replace(str, g =>
                {
                    var key = g.Groups["key"].Value.ToLower();
                    switch (key)
                    {
                        case "user":
                            var Str = "";
                            if (isUser)
                            {
                                using (System.IO.Stream stream2 = typeof(HttpProxy).Assembly
                                                   .GetManifestResourceStream("UMC.ITME.Resources.user.html"))
                                {
                                    Str = new System.IO.StreamReader(stream2).ReadToEnd().Replace("{name}", this.SiteCookie.Account ?? this.Context.Token.Username);
                                }
                                if (this.SiteCookie.IndexValue > 0)
                                {
                                    return Str;
                                }
                                var upConfig = GetConf(String.Format("SITE_MIME_{0}_UPDATE", Site.Root).ToUpper());
                                if (SiteConfig.CheckMime(upConfig))
                                {

                                    switch (this.Site.Site.UserModel ?? Entities.UserModel.Standard)
                                    {
                                        case Entities.UserModel.Check:
                                            return Str;
                                    }

                                    var updateModel = upConfig["UpdateModel"] as string ?? "Selected";
                                    switch (updateModel)
                                    {
                                        case "Select":
                                        case "Selected":
                                        case "Compel":
                                            using (System.IO.Stream stream2 = typeof(HttpProxy).Assembly
                                                             .GetManifestResourceStream($"UMC.ITME.Resources.pwd-{updateModel}.html"))
                                            {
                                                Str += new System.IO.StreamReader(stream2).ReadToEnd();
                                            }
                                            break;
                                        default:
                                            break;
                                    }
                                }


                            }
                            return Str;
                        case "action":
                            var callback = this.Context.QueryString["callback"];

                            if (String.IsNullOrEmpty(callback) == false)
                            {
                                return $"?callback={Uri.EscapeDataString(callback)}";
                            }
                            else if (this.RawUrl.StartsWith("/UMC.Login"))
                            {

                                return "";
                            }
                            else
                            {
                                return $"/UMC.Login/Go?callback={Uri.EscapeDataString(this.RawUrl)}";
                            }
                        case "home":
                            return "";
                        case "title":
                            return isUser ? $"{this.Site.Caption}账户绑定" : $"{this.Site.Caption}登录选择";
                        case "error":
                            return error;
                        case "fields":
                            return UMC.Data.JSON.Serialize(this.FieldHtml(isUser));
                    }
                    return "";

                });
                this.Context.Output.Write(v);

            }
        }

        WebMeta[] FieldHtml(bool isUser)
        {
            var login = GetConf(String.Format("SITE_MIME_{0}_LOGIN", Site.Root).ToUpper());
            var user = this.Context.Token.Identity();

            var hash = new Hashtable();

            var matchEvaluator = Match(hash, isUser ? "{Username}" : this.SiteCookie.Account, "", "");

            var feilds = login["Feilds"] as Hashtable ?? new Hashtable();
            var list = new List<WebMeta>();
            if (feilds.Count > 0)
            {


                var fd = feilds.Keys.Cast<String>().OrderBy(r => r).GetEnumerator();
                while (fd.MoveNext())
                {
                    var fdKey = fd.Current as string;
                    var mainKey = String.Format("SITE_MIME_{0}_LOGIN_{1}", Site.Root, fdKey).ToUpper();
                    var config = GetConf(mainKey);

                    var script = (config["Script"] as string ?? "").Trim();

                    if (script.StartsWith("[") == false)
                    {
                        continue;
                    }
                    this.Isurlencoded = false;
                    var fConfig = new WebMeta().Put("name", fdKey).Put("title", feilds[fdKey]);
                    var changes = new List<String>();
                    var rawUrl = config["RawUrl"] as string;

                    if (String.IsNullOrEmpty(rawUrl) == false)
                    {
                        var getUrl = Regex.Replace(rawUrl, matchEvaluator);
                        var ms = Regex.Matches(getUrl);
                        if (ms.Count > 0)
                        {

                            for (var i = 0; i < ms.Count; i++)
                            {
                                var cKey = ms[i].Groups["key"].Value;
                                if (changes.Exists(c => cKey == c) == false)
                                    changes.Add(cKey);
                            }

                        }

                        var value = config["Content"] as string;
                        var Method = config["Method"] as string;
                        if (String.IsNullOrEmpty(value) == false && String.IsNullOrEmpty(Method) == false)
                        {
                            switch (Method)
                            {
                                case "POST":
                                case "PUT":
                                    var valResult = Regex.Replace(value, matchEvaluator);

                                    ms = Regex.Matches(valResult);
                                    if (ms.Count > 0)
                                    {
                                        for (var i = 0; i < ms.Count; i++)
                                        {
                                            var cKey = ms[i].Groups["key"].Value;
                                            if (changes.Exists(c => cKey == c) == false)
                                                changes.Add(cKey);
                                        }

                                    }
                                    break;
                            }
                        }
                    }
                    if (changes.Count > 0)
                    {
                        fConfig.Put("change", String.Join(",", changes.ToArray()));
                    }
                    else
                    {
                        fConfig.Put("data", UMC.Data.JSON.Expression(GetConfig(config, matchEvaluator)));
                    }
                    list.Add(fConfig);

                }
            }
            return list.OrderBy(r => r["name"]).ToArray();
        }
        Hashtable GetConf(String mainKey)
        {
            var login = new Hashtable();
            var pconfig = UMC.Data.DataFactory.Instance().Config(mainKey);
            if (pconfig != null)
            {
                var v = UMC.Data.JSON.Deserialize(pconfig.ConfValue) as Hashtable;
                if (v != null)
                {
                    login = v;
                }

            }
            return login;
        }
        void Update(Hashtable feildConfig, NameValueCollection form)
        {

            var newPass = UMC.Data.Utility.Guid(Guid.NewGuid());
            var sb = new System.Text.StringBuilder();

            if (this.IsLog == true)
                this.Loger.WriteLine("更新密码:");
            if (XHR(GetConf(String.Format("SITE_MIME_{0}_UPDATE", Site.Root).ToUpper()), form, feildConfig, "UPDATE", newPass))
            {
                var userM = (this.SiteCookie.Model ?? Entities.AccountModel.Standard) | Entities.AccountModel.Changed;
                this.Password = newPass;
                this.SiteCookie.Model = userM;
            }
            else if (sb.Length > 0)
            {
                if (this.IsLog == true)
                {
                    this.Loger.WriteLine(sb.ToString());
                }
            }
        }

        void GetConfig(Hashtable login, MatchEvaluator matchEvaluator, Action<string> action)
        {
            var script = (login["Script"] as string ?? "");

            script = script.Trim();
            if ((script.StartsWith("{") && script.EndsWith("}")) || (script.StartsWith("[") && script.EndsWith("]")))
            {
                action(Regex.Replace(script, matchEvaluator));
                return;
            }
            var rawUrl = login["RawUrl"] as string;
            if (String.IsNullOrEmpty(rawUrl))
            {
                errorMsg = $"未配置请求的Url";
                action("[]");
                return;

            }
            var Header = login["Header"] as string;
            if (String.IsNullOrEmpty(Header) == false)
            {
                this.Isurlencoded = false;
                Header = Regex.Replace(Header, matchEvaluator);
            }

            this.Isurlencoded = true;

            var PathAndQuery = Regex.Replace(rawUrl, matchEvaluator);

            Uri getUrl = Domain;

            var sStrDomain = login["Domain"] as string;

            if (String.IsNullOrEmpty(sStrDomain) == false)
            {
                getUrl = new Uri(sStrDomain);
            }

            var Method = login["Method"] as string;
            if (String.IsNullOrEmpty(Method))
            {
                errorMsg = $"未配置{rawUrl}请求的Method";

                action("[]");
                return;
            }

            String valResult = null;
            var value = (login["Content"] as string) ?? String.Empty;

            var webr = this.Context.Transfer(getUrl);
            webr.RawUrl = PathAndQuery;
            switch (Method)
            {
                case "POST":
                case "PUT":
                    var ContentType = login["ContentType"] as string;
                    if (String.IsNullOrEmpty(ContentType))
                    {
                        errorMsg = $"未配置{rawUrl}请求的ContentType";

                        action("[]");
                        return;
                    }
                    else
                    {
                        webr.ContentType = ContentType;
                        this.Isurlencoded = ContentType.Contains("urlencoded");

                        valResult = Regex.Replace(value, matchEvaluator);


                    }
                    break;
            }

            (this.Domain.Host.Equals(getUrl.Host) ? this.Reqesut(webr) : webr).Header(Header).Net(Method, valResult, res =>
            {
                this.SetCookie(res);
                if (this.IsLog == true)
                {
                    this.Loger.Write(Method);
                    this.Loger.Write(":");
                    this.Loger.WriteLine(getUrl.PathAndQuery);
                    this.Loger.WriteLine(System.Text.UTF8Encoding.UTF8.GetString(webr.Headers.ToByteArray()));

                    this.Loger.WriteLine(valResult);
                    this.Loger.WriteLine();

                    this.Loger.WriteLine("{0} {1} {2}", res.ProtocolVersion, (int)res.StatusCode, res.StatusDescription);

                    this.Loger.WriteLine(Utility.NameValue(res.Headers));
                }

                int statusCode = Convert.ToInt32(res.StatusCode);
                if (statusCode >= 500)
                {
                    LogWrite(this.Context, this.Site, statusCode, String.Format("{0} {1}", Method, getUrl.PathAndQuery), this.SiteCookie.Account, 0, res.Headers, this._AttachmentFile);

                }

                res.ReadAsString(str =>
                {
                    if (this.IsLog == true)
                    {
                        this.Loger.WriteLine(str);
                        this.Loger.WriteLine();
                    }
                    if (res.StatusCode != HttpStatusCode.OK)
                    {
                        action("{}");
                        return;
                    }
                    if (String.IsNullOrEmpty(script) || String.Equals(script, "none", StringComparison.CurrentCultureIgnoreCase))
                    {
                        action("{}");
                        return;
                    }
                    else
                    {
                        action(UMC.Data.JSON.Serialize(GetKeyValue(str, script)));
                    }

                }, this.Context.Error);

            });

        }
        String GetConfig(Hashtable login, MatchEvaluator matchEvaluator)
        {
            var script = (login["Script"] as string ?? "");

            script = script.Trim();
            if ((script.StartsWith("{") && script.EndsWith("}")) || (script.StartsWith("[") && script.EndsWith("]")))
            {
                return Regex.Replace(script, matchEvaluator);
            }
            var rawUrl = login["RawUrl"] as string;
            if (String.IsNullOrEmpty(rawUrl))
            {
                errorMsg = $"未配置请求的Url";
                return "[]";

            }
            var Header = login["Header"] as string;
            if (String.IsNullOrEmpty(Header) == false)
            {
                this.Isurlencoded = false;
                Header = Regex.Replace(Header, matchEvaluator);
            }

            this.Isurlencoded = true;

            var PathAndQuery = Regex.Replace(rawUrl, matchEvaluator);

            Uri getUrl;

            var sStrDomain = login["Domain"] as string;

            if (String.IsNullOrEmpty(sStrDomain) == false)
            {
                getUrl = new Uri(sStrDomain);// new Uri(new, PathAndQuery);

            }
            else
            {
                getUrl = Domain;// new Uri(Domain, PathAndQuery);
            }

            var Method = login["Method"] as string ?? "GET";

            String valResult = null;
            var webr = this.Context.Transfer(getUrl);
            webr.RawUrl = PathAndQuery;
            var value = (login["Content"] as string) ?? String.Empty;
            switch (Method)
            {
                case "POST":
                case "PUT":
                    var ContentType = login["ContentType"] as string;
                    if (String.IsNullOrEmpty(ContentType))
                    {
                        this.Isurlencoded = false;

                    }
                    else
                    {
                        this.Isurlencoded = ContentType.Contains("urlencoded");

                        valResult = Regex.Replace(value, matchEvaluator);


                        webr.ContentType = ContentType;

                    }
                    break;
            }
            var res = (this.Domain.Host.Equals(getUrl.Host) ? this.Reqesut(webr) : webr).Header(Header).Net(Method, valResult);

            this.SetCookie(res);
            var str = res.ReadAsString();
            if (this.IsLog == true)
            {
                this.Loger.Write(Method);
                this.Loger.Write(":");
                this.Loger.WriteLine(PathAndQuery);
                this.Loger.WriteLine(System.Text.UTF8Encoding.UTF8.GetString(webr.Headers.ToByteArray()));

                this.Loger.WriteLine(valResult);
                this.Loger.WriteLine();

                this.Loger.WriteLine("{0} {1} {2}", res.ProtocolVersion, (int)res.StatusCode, res.StatusDescription);

                this.Loger.WriteLine(Utility.NameValue(res.Headers));

                this.Loger.WriteLine(str);
                this.Loger.WriteLine();
            }

            int statusCode = Convert.ToInt32(res.StatusCode);
            if (statusCode >= 500)
            {
                LogWrite(this.Context, this.Site, statusCode, String.Format("{0} {1}", Method, getUrl.PathAndQuery), this.SiteCookie.Account, 0, res.Headers, this._AttachmentFile);

            }
            if (res.StatusCode != HttpStatusCode.OK)
            {
                return "{}";
            }
            if (String.IsNullOrEmpty(script) || String.Equals(script, "none", StringComparison.CurrentCultureIgnoreCase))
            {
                return "{}";
            }
            return UMC.Data.JSON.Serialize(GetKeyValue(str, script));
        }
        Object GetKeyValue(String html, string nvConfig)
        {
            if (nvConfig.StartsWith("[") && nvConfig.Contains("]:"))
            {
                var tfds = new List<String>();

                var keyIndex = nvConfig.IndexOf(':');
                var nv = nvConfig.Substring(0, keyIndex).Trim('[', ']');
                if (String.IsNullOrEmpty(nv) == false)
                {
                    var nvs = nv.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

                    foreach (var k in nvs)
                    {
                        var v = k.Trim();
                        if (String.IsNullOrEmpty(v) == false)
                        {
                            tfds.Add(v);
                        }
                    }
                }

                var keyN = nvConfig.Substring(keyIndex + 1).Trim();


                var sc = UMC.Data.JSON.Deserialize(html);
                Array array = null;
                if (html.StartsWith("["))
                {
                    array = sc as Array;
                }
                else if (sc is Hashtable)
                {
                    var scD = sc as Hashtable;
                    if (scD.ContainsKey(keyN))
                    {
                        array = scD[keyN] as Array;
                    }
                    else
                    {
                        int idex = keyN.IndexOf('.');
                        while (idex > 0)
                        {
                            var k = keyN.Substring(0, idex);
                            if (scD.ContainsKey(k))
                            {
                                scD = scD[k] as Hashtable;
                                keyN = keyN.Substring(idex + 1);
                                if (scD.ContainsKey(keyN))
                                {

                                    array = scD[keyN] as Array;
                                    break;
                                }
                                else
                                {
                                    idex = keyN.IndexOf('.');
                                }
                            }
                        }
                    }
                }
                if (array == null)
                {
                    return new int[0];
                }

                var vField = "";
                if (tfds.Count > 0)
                {
                    vField = tfds[tfds.Count - 1];
                    if (tfds.Count > 1)
                    {
                        tfds.RemoveAt(tfds.Count - 1);
                    }
                }
                var list = new List<WebMeta>();

                foreach (var k in array)
                {
                    if (tfds.Count == 0)
                    {
                        list.Add(new WebMeta().Put("Text", k.ToString(), "Value", k.ToString()));
                    }
                    else if (k is Hashtable)
                    {
                        var kd = k as Hashtable;
                        var tkvs = new List<String>();
                        foreach (var tk in tfds)
                        {
                            var v = kd[tk] as string;
                            if (String.IsNullOrEmpty(v) == false)
                            {
                                tkvs.Add(v);
                            }
                        }
                        list.Add(new WebMeta().Put("Text", String.Join("-", tkvs.ToArray())).Put("Value", kd[vField]));

                    }
                }
                return list;

            }
            var nas = SiteConfig.Config(nvConfig);
            var isKey = nas.Contains("KEY-VALUE");
            var vnvs = new Hashtable();

            var formValues = Utility.FromValue(html, isKey);
            var isError = false;
            int valueCount = 0;
            foreach (var name in nas)
            {
                if (String.Equals(name, "KEY-VALUE"))
                {
                    continue;
                }
                else if (String.Equals(name, "KEY-ERROR"))
                {
                    isError = true;
                    continue;
                }
                valueCount++;
                if (formValues.ContainsKey(name))
                {
                    vnvs[name] = formValues[name];
                }
                else
                {
                    int sIndex = html.IndexOf(name);
                    if (sIndex > 1 && sIndex + name.Length < html.Length)
                    {
                        sIndex = sIndex + name.Length;
                        switch (html[sIndex])
                        {
                            case ' ':
                            case '"':
                            case '\'':
                                if (html[sIndex - 1 - name.Length] == html[sIndex])
                                {

                                    while (sIndex < html.Length)
                                    {
                                        sIndex++;
                                        switch (html[sIndex])
                                        {
                                            case '\r':
                                            case '\t':
                                            case '\n':
                                            case ' ':
                                                break;
                                            case ':':
                                            case '=':
                                                var str = GetHtmlValue(html, sIndex + 1);
                                                if (String.IsNullOrEmpty(str) == false)
                                                {
                                                    vnvs[name.Trim(':', '\'', '"', '=').Trim()] = str;
                                                }
                                                sIndex = html.Length;
                                                break;
                                        }
                                    }
                                }
                                break;
                            case ':':
                            case '=':
                                var str2 = GetHtmlValue(html, sIndex + 1);
                                if (String.IsNullOrEmpty(str2) == false)
                                {
                                    vnvs[name.Trim(':', '\'', '"', '=').Trim()] = str2;
                                }
                                break;
                        }
                    }
                }

            }
            if (isError && vnvs.Count != valueCount)
            {
                return "未获取正确的参数";
            }
            return vnvs;
        }
        string GetHtmlValue(string html, int nIndex)
        {

            int start = 0, end = 0;
            char? startStr = null;

            while (nIndex < html.Length)
            {
                switch (html[nIndex])
                {
                    case '\r':
                    case '\t':
                    case '\n':
                    case ' ':

                        if (start > 0 && startStr.HasValue == false)
                        {
                            end = nIndex;
                        }
                        break;
                    case ';':
                    case ',':
                        if (startStr.HasValue == false)
                        {
                            end = nIndex;
                        }
                        break;
                    case '"':
                    case '\'':
                        if (start == 0)
                        {
                            start = nIndex + 1;
                            startStr = html[nIndex];

                        }
                        else if (html[nIndex] == startStr)
                        {
                            end = nIndex;
                        }
                        break;
                    case '}':
                        if (start > 0 && startStr.HasValue == false)
                        {
                            end = nIndex;
                        }
                        break;
                    default:
                        if (start == 0)
                        {
                            start = nIndex;
                        }
                        break;
                }
                if (end > 0)
                {
                    break;
                }
                nIndex++;
            }
            if (start > 0 && start < end)
            {
                return html.Substring(start, end - start);
            }
            return null;

        }

        bool IsLog;

        String errorMsg;
        void SetCookie(string c)
        {
            var index = c.IndexOf('=');
            if (index > 0)
            {
                var name = c.Substring(0, index + 1);
                var isIndex = this.Cookies.IndexOf(name);
                if (isIndex > -1)
                {
                    var end = this.Cookies.IndexOf(';', isIndex);

                    if (end > 0)
                    {
                        this.Cookies = this.Cookies.Remove(isIndex, end - isIndex + 2);
                    }
                    else
                    {
                        this.Cookies = this.Cookies.Remove(isIndex, this.Cookies.Length - isIndex).Trim(' ', ';');
                    }

                }
                var endex = c.IndexOf(';');
                if (endex > 0)
                {
                    var cValue = c.Substring(0, endex);

                    if (String.IsNullOrEmpty(this.Cookies))
                    {
                        this.Cookies = cValue;
                    }
                    else
                    {
                        this.Cookies = $"{this.Cookies}; {cValue}";
                    }
                }
                var i = OuterCookies.FindIndex(r => r.Substring(0, r.IndexOf('=') + 1) == name);
                if (i > -1)
                {
                    OuterCookies[i] = c;
                }
                else
                {
                    OuterCookies.Add(c);
                }
            }

        }
        void SetCookie(NetHttpResponse response)
        {
            var cs = response.Headers.GetValues("Set-Cookie");
            if (cs != null)
            {
                foreach (var c in cs)
                {
                    this.SetCookie(c);
                }
            }
        }
        String ResetPasswork(Hashtable loginConfig, NameValueCollection form, SiteConfig siteConfig)
        {

            if (String.IsNullOrEmpty(siteConfig.Site.Account))
            {
                if (this.IsLog == true)
                    this.Loger.WriteLine("未配置检测账户");
                return null;
            }


            var proxy = new HttpProxy(this, siteConfig);


            var checkConfig = GetConf(String.Format("SITE_MIME_{0}_CHECK", proxy.Site.Root).ToUpper());
            if (checkConfig.ContainsKey("Finish"))
            {

                // if (String.IsNullOrEmpty(proxy.Site.Home) == false && proxy.Site.Home.StartsWith("http") == false)
                // {
                //     var r = proxy.Reqesut(this.Context.Transfer(new Uri(proxy.Domain, proxy.Site.Home))).Get();

                //     proxy.SetCookie(r);

                // }
                var config = new Hashtable();

                if (proxy.IsLog == true)
                {
                    this.Loger.WriteLine("管理员登录:");
                }
                if (checkConfig.ContainsKey("IsNotLoginApi") || proxy.XHR(loginConfig, form, config, "LOGIN", ""))
                {

                    var newPass = UMC.Data.Utility.Guid(Guid.NewGuid());

                    config["Account"] = this.Context.Token.Username;
                    if (proxy.IsLog == true)
                    {
                        proxy.Loger.WriteLine("检测账户密码:");
                    }
                    if (proxy.XHR(checkConfig, form, config, "CHECK", newPass))
                    {
                        if (config.ContainsKey("ResetPasswork"))
                        {
                            return config["ResetPasswork"] as string;
                        }
                        return newPass;
                    }
                    else if (this.IsLog == true)
                    {
                        this.Loger.WriteLine(this.errorMsg);
                    }

                }
                else
                {
                    errorMsg = "检测账户登录失败导致不能重置密码,请联系应用管理员";

                    if (this.IsLog == true)
                    {
                        this.Loger.WriteLine("管理员账户密码不正确");
                    }
                }
            }
            else
            {
                if (this.IsLog == true)
                {
                    this.Loger.WriteLine("未配置完善账户检测接口");
                }

            }
            return null;
        }

        static Regex Regex = new Regex("\\{(?<key>[\\w\\.\\$,\\[\\]_-]+)\\}");
        bool Isurlencoded = true;
        bool XHR(Hashtable login, NameValueCollection form, Hashtable FeildConfig, String fieldKey, String newPass)
        {
            NetHttpResponse response = null;
            try
            {
                return XHR(login, form, FeildConfig, fieldKey, newPass, out response);
            }
            finally
            {
                response?.ReadAsString();
            }
        }

        String GetValue(String key, IDictionary FeildConfig, String newPWd)
        {
            switch (key.ToLower())
            {
                case "user":
                    return this.SiteCookie.Account;
                case "pwd":
                    return this.Password;
                case "new":
                    return newPWd;

            }
            return FeildConfig[key] as string;
        }
        MatchEvaluator Match(Hashtable FeildConfig, String newPass)
        {
            return Match(FeildConfig, this.SiteCookie.Account, this.Password, newPass);
        }
        MatchEvaluator Match(Hashtable FeildConfig, String user, String pd, String newPass)
        {
            Func<String, String> func = (key) =>
             {

                 switch (key.ToLower())
                 {

                     case "user":
                     case "username":
                         return Isurlencoded ? Uri.EscapeDataString(user) : user;
                     case "pwd":
                     case "password":
                         return Isurlencoded ? Uri.EscapeDataString(pd ?? "") : (pd ?? "");
                     case "md5pwd":
                         return UMC.Data.Utility.MD5(pd);
                     case "md5new":
                         return UMC.Data.Utility.MD5(newPass);
                     case "newpwd":
                     case "new":
                         return Isurlencoded ? Uri.EscapeDataString(newPass) : newPass;
                     case "time":
                         return UMC.Data.Utility.TimeSpan().ToString();
                     case "mtime":
                         return UMC.Data.Reflection.TimeSpanMilli(DateTime.Now).ToString();
                     default:
                         var nIndex = key.IndexOf('.');
                         if (nIndex > 0)
                         {
                             string fvalue = "";
                             switch (key.Substring(0, nIndex))
                             {
                                 case "hex":
                                     key = key.Substring(4);
                                     fvalue = GetValue(key, FeildConfig, newPass);
                                     if (String.IsNullOrEmpty(fvalue) == false)
                                     {
                                         return UMC.Data.Utility.Hex(System.Text.Encoding.UTF8.GetBytes(fvalue));
                                     }
                                     break;
                                 case "b64":
                                     key = key.Substring(4);
                                     fvalue = GetValue(key, FeildConfig, newPass);
                                     if (String.IsNullOrEmpty(fvalue) == false)
                                     {
                                         if (this.Isurlencoded)
                                         {
                                             return Uri.EscapeDataString(Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(fvalue)));
                                         }
                                         else
                                         {
                                             return (Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(fvalue)));
                                         }
                                     }
                                     break;
                                 case "md5":
                                     key = key.Substring(4);
                                     {
                                         var isb64 = false;
                                         if (key.EndsWith(".b64"))
                                         {
                                             isb64 = true;
                                             key = key.Substring(0, key.Length - 4);
                                         }

                                         fvalue = GetValue(key, FeildConfig, newPass);
                                         if (String.IsNullOrEmpty(fvalue) == false)
                                         {
                                             byte[] mdata;
                                             using (var md5 = System.Security.Cryptography.MD5.Create())
                                             {
                                                 mdata = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(fvalue));
                                             }
                                             if (isb64)
                                             {
                                                 if (this.Isurlencoded)
                                                 {
                                                     return Uri.EscapeDataString(Convert.ToBase64String(mdata));
                                                 }
                                                 else
                                                 {
                                                     return Convert.ToBase64String(mdata);
                                                 }
                                             }
                                             else
                                             {
                                                 return UMC.Data.Utility.Hex(mdata);

                                             }
                                         }
                                     }
                                     break;

                                 case "s256":
                                     key = key.Substring(5);
                                     {
                                         var isb64 = false;
                                         if (key.EndsWith(".b64"))
                                         {
                                             isb64 = true;
                                             key = key.Substring(0, key.Length - 4);
                                         }
                                         fvalue = GetValue(key, FeildConfig, newPass);
                                         if (String.IsNullOrEmpty(fvalue) == false)
                                         {

                                             var mdata = SHA256.Create().ComputeHash(System.Text.Encoding.UTF8.GetBytes(fvalue));
                                             if (isb64)
                                             {
                                                 if (this.Isurlencoded)
                                                 {
                                                     return Uri.EscapeDataString(Convert.ToBase64String(mdata));
                                                 }
                                                 else
                                                 {
                                                     return Convert.ToBase64String(mdata);
                                                 }
                                             }
                                             else
                                             {
                                                 return UMC.Data.Utility.Hex(mdata);

                                             }
                                         }
                                     }
                                     break;
                                 case "sha1":
                                     key = key.Substring(5);
                                     {
                                         var isb64 = false;
                                         if (key.EndsWith(".b64"))
                                         {
                                             isb64 = true;
                                             key = key.Substring(0, key.Length - 4);
                                         }
                                         fvalue = GetValue(key, FeildConfig, newPass);
                                         if (String.IsNullOrEmpty(fvalue) == false)
                                         {
                                             var mdata = SHA1.Create().ComputeHash(System.Text.Encoding.UTF8.GetBytes(fvalue));
                                             if (isb64)
                                             {
                                                 if (this.Isurlencoded)
                                                 {
                                                     return Uri.EscapeDataString(Convert.ToBase64String(mdata));
                                                 }
                                                 else
                                                 {
                                                     return Convert.ToBase64String(mdata);
                                                 }
                                             }
                                             else
                                             {
                                                 return UMC.Data.Utility.Hex(mdata);
                                             }

                                         }
                                     }
                                     break;
                                 case "hmac":
                                     key = key.Substring(5);
                                     nIndex = key.IndexOf('.');
                                     if (nIndex > 0)
                                     {

                                         var bpwd = FeildConfig[(key.Substring(0, nIndex))] as string;
                                         if (String.IsNullOrEmpty(bpwd) == false)
                                         {
                                             key = key.Substring(nIndex + 1);

                                             var isb64 = false;
                                             if (key.EndsWith(".b64"))
                                             {
                                                 isb64 = true;
                                                 key = key.Substring(0, key.Length - 4);
                                             }


                                             fvalue = GetValue(key, FeildConfig, newPass);
                                             if (String.IsNullOrEmpty(fvalue) == false)
                                             {
                                                 var mdata = new HMACSHA1(Encoding.UTF8.GetBytes(bpwd)).ComputeHash(Encoding.UTF8.GetBytes(fvalue));

                                                 if (isb64)
                                                 {
                                                     if (this.Isurlencoded)
                                                     {
                                                         return Uri.EscapeDataString(Convert.ToBase64String(mdata));
                                                     }
                                                     else
                                                     {
                                                         return Convert.ToBase64String(mdata);
                                                     }
                                                 }
                                                 else
                                                 {
                                                     return UMC.Data.Utility.Hex(mdata);
                                                 }
                                             }
                                         }
                                     }
                                     break;
                                 case "aes":
                                     key = key.Substring(4);
                                     nIndex = key.IndexOf('.');
                                     if (nIndex > 0)
                                     {
                                         var nkey = FeildConfig[key.Substring(0, nIndex)] as string;
                                         if (String.IsNullOrEmpty(nkey) == false)
                                         {
                                             key = key.Substring(nIndex + 1);
                                             var isb64 = false;
                                             if (key.EndsWith(".b64"))
                                             {
                                                 isb64 = true;
                                                 key = key.Substring(0, key.Length - 4);
                                             }
                                             var keys = key.Split('.');
                                             switch (keys.Length)
                                             {
                                                 case 1:
                                                     fvalue = GetValue(keys[0], FeildConfig, newPass);
                                                     if (String.IsNullOrEmpty(fvalue) == false)
                                                     {
                                                         if (isb64)
                                                         {
                                                             if (this.Isurlencoded)
                                                             {
                                                                 return Uri.EscapeDataString(Convert.ToBase64String(UMC.Data.Utility.AES(fvalue, nkey, 1)));
                                                             }
                                                             else
                                                             {
                                                                 return Convert.ToBase64String(UMC.Data.Utility.AES(fvalue, nkey, 1));
                                                             }
                                                         }
                                                         else
                                                         {
                                                             return UMC.Data.Utility.Hex(UMC.Data.Utility.AES(fvalue, nkey, 1));
                                                         }
                                                     }
                                                     break;
                                                 case 2:
                                                     var iv = FeildConfig[keys[0]] as string;
                                                     fvalue = GetValue(keys[1], FeildConfig, newPass);
                                                     if (String.IsNullOrEmpty(fvalue) == false)
                                                     {
                                                         if (String.IsNullOrEmpty(iv))
                                                         {
                                                             var iterations = UMC.Data.Utility.IntParse(keys[0], -1);
                                                             if (iterations > 0)
                                                             {
                                                                 if (isb64)
                                                                 {
                                                                     if (this.Isurlencoded)
                                                                     {
                                                                         return Uri.EscapeDataString(Convert.ToBase64String(UMC.Data.Utility.AES(fvalue, nkey, iterations)));
                                                                     }
                                                                     else
                                                                     {
                                                                         return Convert.ToBase64String(UMC.Data.Utility.AES(fvalue, nkey, iterations));
                                                                     }
                                                                 }
                                                                 else
                                                                 {
                                                                     return UMC.Data.Utility.Hex(UMC.Data.Utility.AES(fvalue, nkey, iterations));
                                                                 }
                                                             }
                                                         }
                                                         else
                                                         {
                                                             if (isb64)
                                                             {
                                                                 if (this.Isurlencoded)
                                                                 {
                                                                     return Uri.EscapeDataString(Convert.ToBase64String(UMC.Data.Utility.AES(fvalue, nkey, iv)));
                                                                 }
                                                                 else
                                                                 {
                                                                     return Convert.ToBase64String(UMC.Data.Utility.AES(fvalue, nkey, iv));
                                                                 }
                                                             }
                                                             else
                                                             {
                                                                 return UMC.Data.Utility.Hex(UMC.Data.Utility.AES(fvalue, nkey, iv));
                                                             }
                                                         }
                                                     }
                                                     break;
                                             }
                                         }
                                     }

                                     break;
                                 case "des":
                                     key = key.Substring(4);
                                     nIndex = key.IndexOf('.');
                                     if (nIndex > 0)
                                     {
                                         var nkey = FeildConfig[key.Substring(0, nIndex)] as string;
                                         if (String.IsNullOrEmpty(nkey) == false)
                                         {
                                             key = key.Substring(nIndex + 1);
                                             var isb64 = false;
                                             if (key.EndsWith(".b64"))
                                             {
                                                 isb64 = true;
                                                 key = key.Substring(0, key.Length - 4);
                                             }
                                             var keys = key.Split('.');
                                             switch (keys.Length)
                                             {
                                                 case 1:
                                                     fvalue = GetValue(keys[0], FeildConfig, newPass);
                                                     if (String.IsNullOrEmpty(fvalue) == false)
                                                     {
                                                         if (isb64)
                                                         {
                                                             if (this.Isurlencoded)
                                                             {
                                                                 return Uri.EscapeDataString(Convert.ToBase64String(UMC.Data.Utility.DES(fvalue, nkey, 1)));
                                                             }
                                                             else
                                                             {
                                                                 return Convert.ToBase64String(UMC.Data.Utility.DES(fvalue, nkey, 1));
                                                             }
                                                         }
                                                         else
                                                         {
                                                             return UMC.Data.Utility.Hex(UMC.Data.Utility.DES(fvalue, nkey, 1));
                                                         }
                                                     }
                                                     break;
                                                 case 2:
                                                     var iv = FeildConfig[keys[0]] as string;
                                                     fvalue = GetValue(keys[1], FeildConfig, newPass);
                                                     if (String.IsNullOrEmpty(fvalue) == false)
                                                     {
                                                         if (String.IsNullOrEmpty(iv))
                                                         {
                                                             var iterations = UMC.Data.Utility.IntParse(keys[0], -1);
                                                             if (iterations > 0)
                                                             {
                                                                 if (isb64)
                                                                 {
                                                                     if (this.Isurlencoded)
                                                                     {
                                                                         return Uri.EscapeDataString(Convert.ToBase64String(UMC.Data.Utility.DES(fvalue, nkey, iterations)));
                                                                     }
                                                                     else
                                                                     {
                                                                         return Convert.ToBase64String(UMC.Data.Utility.DES(fvalue, nkey, iterations));
                                                                     }
                                                                 }
                                                                 else
                                                                 {
                                                                     return UMC.Data.Utility.Hex(UMC.Data.Utility.DES(fvalue, nkey, iterations));
                                                                 }
                                                             }
                                                         }
                                                         else
                                                         {
                                                             if (isb64)
                                                             {
                                                                 if (this.Isurlencoded)
                                                                 {
                                                                     return Uri.EscapeDataString(Convert.ToBase64String(UMC.Data.Utility.DES(fvalue, nkey, iv)));
                                                                 }
                                                                 else
                                                                 {
                                                                     return Convert.ToBase64String(UMC.Data.Utility.DES(fvalue, nkey, iv));
                                                                 }
                                                             }
                                                             else
                                                             {
                                                                 return UMC.Data.Utility.Hex(UMC.Data.Utility.DES(fvalue, nkey, iv));
                                                             }
                                                         }
                                                     }
                                                     break;
                                             }
                                         }
                                     }

                                     break;
                                 case "pem":
                                     key = key.Substring(4);
                                     nIndex = key.IndexOf('.');
                                     if (nIndex > 0)
                                     {
                                         var pem = FeildConfig[key.Substring(0, nIndex)] as string;
                                         if (String.IsNullOrEmpty(pem) == false)
                                         {
                                             key = key.Substring(nIndex + 1);

                                             var isb64 = false;
                                             if (key.EndsWith(".b64"))
                                             {
                                                 isb64 = true;
                                                 key = key.Substring(0, key.Length - 4);
                                             }
                                             fvalue = GetValue(key, FeildConfig, newPass);
                                             if (String.IsNullOrEmpty(fvalue) == false)
                                             {
                                                 if (isb64)
                                                 {
                                                     if (this.Isurlencoded)
                                                     {
                                                         return Uri.EscapeDataString(Convert.ToBase64String(UMC.Data.Utility.RSA(pem, fvalue)));
                                                     }
                                                     else
                                                     {
                                                         return Convert.ToBase64String(UMC.Data.Utility.RSA(pem, fvalue));
                                                     }
                                                 }
                                                 else
                                                 {
                                                     return UMC.Data.Utility.Hex(UMC.Data.Utility.RSA(pem, fvalue));
                                                 }
                                             }

                                         }
                                     }
                                     break;
                                 case "rsa":
                                     key = key.Substring(4);
                                     nIndex = key.IndexOf('.');
                                     if (nIndex > 0)
                                     {
                                         var n = FeildConfig[key.Substring(0, nIndex)] as string;
                                         if (String.IsNullOrEmpty(n) == false)
                                         {
                                             var isb64 = false;
                                             if (key.EndsWith(".b64"))
                                             {
                                                 isb64 = true;
                                                 key = key.Substring(0, key.Length - 4);
                                             }
                                             key = key.Substring(nIndex + 1);
                                             nIndex = key.IndexOf('.');

                                             if (nIndex > 0)
                                             {
                                                 var e = FeildConfig[key.Substring(0, nIndex)] as string;
                                                 key = key.Substring(nIndex + 1);

                                                 fvalue = GetValue(key, FeildConfig, newPass);
                                                 if (fvalue != null)
                                                 {
                                                     if (isb64)
                                                     {
                                                         if (this.Isurlencoded)
                                                         {
                                                             return Uri.EscapeDataString(Convert.ToBase64String(UMC.Data.Utility.RSA(n, e, fvalue)));
                                                         }
                                                         else
                                                         {
                                                             return Convert.ToBase64String(UMC.Data.Utility.RSA(n, e, fvalue));
                                                         }
                                                     }
                                                     else
                                                     {
                                                         return UMC.Data.Utility.Hex(UMC.Data.Utility.RSA(n, e, fvalue));
                                                     }
                                                 }
                                             }
                                         }
                                     }

                                     break;
                             }
                         }

                         if (FeildConfig.ContainsKey(key))
                         {
                             return Isurlencoded ? Uri.EscapeDataString(FeildConfig[key] as string ?? "") : FeildConfig[key] as string;
                         }
                         else
                         {
                             var cookie = this.Context.Cookies[key];
                             if (String.IsNullOrEmpty(cookie) == false)
                             {
                                 return Isurlencoded ? Uri.EscapeDataString(cookie) : cookie;
                             }
                         }
                         return null;
                 }
             };

            MatchEvaluator matchEvaluator = r =>
            {

                var key = r.Groups["key"].Value;
                var kIndex = key.IndexOf('[');
                if (kIndex > 0)
                {
                    var value = func(key.Substring(0, kIndex));
                    if (value == null)
                    {
                        return r.Value;
                    }
                    else
                    {
                        var sValue = key.Substring(kIndex + 1).Trim('[', ']').Trim().Split(',');

                        switch (sValue.Length)
                        {
                            case 1:
                                return value.Substring(UMC.Data.Utility.IntParse(sValue[0], 0));
                            case 2:
                                return value.Substring(UMC.Data.Utility.IntParse(sValue[0], 0), UMC.Data.Utility.IntParse(sValue[1], value.Length));

                            default:
                                return r.Value;
                        }

                    }
                }
                else
                {
                    return func(key) ?? r.Value;
                }

            };
            return matchEvaluator;
        }
        string _LoginRedirectLocation;
        bool XHR(Hashtable login, NameValueCollection form, Hashtable FeildConfig, String fieldKey, String newPass, out NetHttpResponse httpResponse)
        {
            errorMsg = String.Empty;
            httpResponse = null;
            if (login.ContainsKey("Finish"))
            {

                if (String.IsNullOrEmpty(this.SiteCookie.Account) && this.Password == null)
                {
                    return false;
                }
                var username = this.SiteCookie.Account;
                var Password = this.Password;

                var matchEvaluator = Match(FeildConfig, newPass);

                this.Isurlencoded = true;
                var feilds = login["Feilds"] as Hashtable ?? new Hashtable();
                if (feilds.Count > 0)
                {
                    var fd = feilds.Keys.Cast<String>().OrderBy(r => r).GetEnumerator();
                    while (fd.MoveNext())
                    {
                        var fdKey = fd.Current;
                        if (fdKey == "LoginAfter")
                        {
                            continue;
                        }

                        var fvalue = form.Get(fdKey);
                        if (String.IsNullOrEmpty(fvalue))
                        {

                            var conf = GetConf($"SITE_MIME_{Site.Root}_{fieldKey}_{fdKey}".ToUpper());

                            var obj = UMC.Data.JSON.Deserialize(GetConfig(conf, matchEvaluator));

                            if (obj is Array)
                            {
                                Array array = obj as Array;
                                switch (array.Length)
                                {
                                    case 0:
                                        return false;
                                    case 1:
                                        var h = array.GetValue(0) as Hashtable;
                                        if (h != null)
                                        {
                                            var fValue = h["Value"] as string;
                                            FeildConfig[fdKey] = h["Value"];
                                            if (String.IsNullOrEmpty(fValue))
                                            {
                                                errorMsg = $"获取到{feilds[fdKey]}的格式不正确";
                                                return false;
                                            }
                                        }
                                        else
                                        {
                                            errorMsg = $"获取到{feilds[fdKey]}的格式不正确";
                                            return false;
                                        }
                                        break;
                                    default:
                                        if (conf.ContainsKey("RememberValue") == false || FeildConfig.ContainsKey(fdKey) == false)
                                        {

                                            if (conf.Contains("DefautValue"))
                                            {
                                                var sKey = SiteConfig.Config(conf["DefautValue"] as string);
                                                if (sKey.Length > 0)
                                                {
                                                    int iNdex = 0;
                                                    for (; iNdex < array.Length; iNdex++)
                                                    {
                                                        var val = array.GetValue(iNdex) as Hashtable;
                                                        if (val != null)
                                                        {
                                                            var fValue = val["Value"] as string;
                                                            if (String.Equals(fValue, sKey[0]))
                                                            {
                                                                FeildConfig[fdKey] = fValue;
                                                                FeildConfig[fdKey + "_Text"] = val["Text"];
                                                                break;
                                                            }
                                                        }
                                                    }
                                                    if (iNdex == array.Length)
                                                    {
                                                        errorMsg = $"请选择{feilds[fdKey]}";
                                                        return false;
                                                    }
                                                }
                                                else
                                                {
                                                    errorMsg = $"请选择{feilds[fdKey]}";
                                                    return false;
                                                }
                                            }
                                            else
                                            {
                                                errorMsg = $"请选择{feilds[fdKey]}";
                                                return false;
                                            }
                                        }
                                        break;
                                }
                            }
                            else if (obj is Hashtable)
                            {
                                var ms = (obj as Hashtable).GetEnumerator();
                                while (ms.MoveNext())
                                {
                                    FeildConfig[ms.Key] = ms.Value;
                                }
                            }
                            else
                            {
                                errorMsg = $"获取到{feilds[fdKey]}的格式不正确";
                                return false;
                            }
                        }
                        else
                        {
                            String fText = form.Get(fdKey + "_Text");
                            if (String.IsNullOrEmpty(fText) == false)
                            {

                                FeildConfig[fdKey + "_Text"] = fText;
                            }
                            FeildConfig[fdKey] = fvalue;
                        }
                    }

                }
                var rawUrl = login["RawUrl"] as string;
                if (String.IsNullOrEmpty(rawUrl))
                {
                    errorMsg = "接口请求地址未配置";
                    return false;

                }

                var Header = login["Header"] as string;
                if (String.IsNullOrEmpty(Header) == false)
                {
                    this.Isurlencoded = false;
                    Header = Regex.Replace(Header, matchEvaluator);
                }

                this.Isurlencoded = true;


                var PathAndQuery = Regex.Replace(rawUrl, matchEvaluator);

                Uri getUrl = null;

                var sStrDomain = login["Domain"] as string;

                if (String.IsNullOrEmpty(sStrDomain) == false)
                {
                    getUrl = new Uri(sStrDomain);
                }
                else
                {
                    getUrl = Domain;//new Uri(Domain, PathAndQuery);
                }
                var Method = login["Method"] as string ?? "GET";

                var webR = this.Context.Transfer(getUrl).Header(Header);
                webR.RawUrl = PathAndQuery;
                String valResult = null;
                switch (Method)
                {
                    case "POST":
                    case "PUT":
                        var value = (login["Content"] as string) ?? String.Empty;
                        var ContentType = login["ContentType"] as string;
                        if (String.IsNullOrEmpty(ContentType))
                        {
                            this.Isurlencoded = false;
                        }
                        else
                        {
                            this.Isurlencoded = ContentType.Contains("urlencoded");
                            valResult = Regex.Replace(value, matchEvaluator);
                            webR.ContentType = ContentType;

                        }
                        break;
                }
                httpResponse = this.Reqesut(webR).Net(Method, valResult);
                if (this.IsLog == true)
                {
                    this.Loger.Write(Method);
                    this.Loger.Write(":");
                    this.Loger.WriteLine(PathAndQuery);
                    this.Loger.WriteLine(Utility.NameValue(webR.Headers));
                    this.Loger.WriteLine(valResult);
                    this.Loger.WriteLine();

                    this.Loger.WriteLine("{0} {1} {2}", httpResponse.ProtocolVersion, (int)httpResponse.StatusCode, httpResponse.StatusDescription);
                    this.Loger.WriteLine(Utility.NameValue(httpResponse.Headers));
                    this.Loger.WriteLine();
                }


                this.SetCookie(httpResponse);
                var finish = login["Finish"] as string;

                if (finish.StartsWith("H:"))
                {
                    var key = finish.Substring(2);
                    var keyIndex = key.IndexOf(':');
                    if (keyIndex > 0)
                    {
                        var v = key.Substring(keyIndex + 1).Trim();
                        key = key.Substring(0, keyIndex);
                        var keyValue = httpResponse.Headers.Get(key);
                        if (String.IsNullOrEmpty(keyValue) == false)
                        {
                            if (String.Equals(keyValue, v))
                            {
                                return true;

                            }
                        }
                    }
                    else if (String.IsNullOrEmpty(httpResponse.Headers.Get(key)) == false)
                    {
                        return true;
                    }
                }
                else if (finish.StartsWith("HE:"))
                {
                    var key = finish.Substring(3);
                    var keyIndex = key.IndexOf(':');
                    if (keyIndex > 0)
                    {
                        var v = key.Substring(keyIndex + 1).Trim();
                        key = key.Substring(0, keyIndex);
                        var keyValue = httpResponse.Headers.Get(key);
                        if (String.IsNullOrEmpty(keyValue) == false)
                        {
                            if (String.Equals(keyValue, v) == false)
                            {
                                return true;
                            }

                        }
                    }
                    else if (String.IsNullOrEmpty(httpResponse.Headers.Get(key)))
                    {
                        return true;
                    }
                }
                else
                {
                    switch (httpResponse.StatusCode)
                    {
                        case HttpStatusCode.Redirect:
                        case HttpStatusCode.RedirectKeepVerb:
                        case HttpStatusCode.RedirectMethod:
                            _LoginRedirectLocation = httpResponse.Headers.Get("Location");
                            if (String.Equals("Url", finish))
                            {
                                return true;
                            }
                            break;
                        case HttpStatusCode.OK:

                            _CheckBody = httpResponse.ReadAsString();

                            if (this.IsLog == true)
                            {
                                this.Loger.WriteLine(_CheckBody);
                                this.Loger.WriteLine();
                            }
                            if (finish.StartsWith("E:"))
                            {
                                if (_CheckBody.Contains(finish.Substring(2)) == false)
                                {
                                    return true;

                                }
                            }
                            else if (String.Equals("Url", finish) == false)
                            {
                                var vs = finish.Split('|', StringSplitOptions.RemoveEmptyEntries);
                                for (var i = 0; i < vs.Length; i++)
                                {
                                    if (_CheckBody.Contains(vs[i]))
                                    {
                                        return true;
                                    }
                                }
                            }
                            break;
                        default:

                            int statusCode = Convert.ToInt32(httpResponse.StatusCode);
                            if (statusCode >= 500)
                            {
                                LogWrite(this.Context, this.Site, statusCode, String.Format("{0} {1}", Method, getUrl.PathAndQuery), this.SiteCookie.Account, 0, httpResponse.Headers, _AttachmentFile);

                            }
                            if (this.IsLog == true)
                            {
                                this.Loger.WriteLine(httpResponse.ReadAsString());
                                this.Loger.WriteLine();
                            }
                            return false;

                    }


                }
                return false;
            }
            else
            {
                errorMsg = "接口配置未完善";
                return false;
            }

        }

        String _CheckBody;

        bool Login(bool isHome, bool isBody, NameValueCollection form, String apiKey)
        {

            var username = form.Get("Username");
            this.Password = form.Get("Password");

            if (String.IsNullOrEmpty(username) == false)
            {
                this.SiteCookie.Account = username;
            }
            var user = this.Context.Token.Identity();

            if (this.Site.Site.UserModel == Entities.UserModel.Quote)
            {
                if (this.SiteCookie.IndexValue == 0)
                {

                    if (String.IsNullOrEmpty(this.Site.Site.Account) == false && this.Site.Site.Account.StartsWith("@"))
                    {
                        var root = this.Site.Site.Account.Substring(1);
                        this.SiteCookie.Account = user.Name;
                        this.Password = UMC.Data.DataFactory.Instance().Password(SiteConfig.MD5Key(root, this.SiteCookie.user_id.Value, 0));
                        if (String.IsNullOrEmpty(Password))
                        {
                            var home = Data.WebResource.Instance().WebDomain();
                            this.Context.Redirect($"{this.Context.Url.Scheme}://{this.Site.Site.Account.Substring(1)}.{home}/UMC.Login?callback={Uri.EscapeDataString(this.Context.Url.AbsoluteUri)}");
                            return true;
                        }
                    }
                    else
                    {
                        WebServlet.Error(this.Context, "登录异常", String.Format("{0}应用引用模式设置错误，请联系管理员", this.Site.Caption, this.SiteCookie.Account));
                        return true;
                    }
                }


            }
            if (String.IsNullOrEmpty(this.SiteCookie.Account) == false && this.Password == null)
            {
                this.Password = UMC.Data.DataFactory.Instance().Password(SiteConfig.MD5Key(Site.Root, this.SiteCookie.user_id.Value, this.SiteCookie.IndexValue ?? 0));
                this.sourceUP = String.Format("{0}{1}", this.SiteCookie.Account, this.Password);

            }
            var login = GetConf(String.Format("SITE_MIME_{0}_LOGIN", Site.Root).ToUpper());
            var autoCheck = false;
            if (String.IsNullOrEmpty(this.SiteCookie.Account) || this.Password == null)
            {
                if (this.SiteCookie.IndexValue > 0)
                {
                    LoginHtml("", true);
                    return true;
                }
                switch (this.Site.Site.UserModel ?? Entities.UserModel.Standard)
                {
                    case Entities.UserModel.Standard:

                        if (login.ContainsKey("Finish"))
                        {
                            LoginHtml("", true);
                        }
                        else
                        {
                            this.Context.Redirect(this.Site.Site.Home ?? "/");
                        }

                        return true;
                    case Entities.UserModel.Checked:

                        this.SiteCookie.Account = user.Name;
                        this.Password = this.ResetPasswork(login, form, this.Site);
                        if (this.Password == null)
                        {
                            WebServlet.Error(this.Context, "登录异常", String.IsNullOrEmpty(errorMsg) ? String.Format("应用中未检测到{1}账户，请联系{0}应用管理员确认账户", this.Site.Caption, this.SiteCookie.Account) : errorMsg);
                            return true;
                        }
                        autoCheck = true;
                        this.SiteCookie.Model = (this.SiteCookie.Model ?? Entities.AccountModel.Standard) | Entities.AccountModel.Check | Entities.AccountModel.Changed;
                        this.SiteCookie.ChangedTime = 0;

                        break;

                    case Entities.UserModel.Check:

                        switch (apiKey)
                        {
                            case "Input":
                                LoginHtml("", true);
                                return true;
                            case "Auto":
                                this.SiteCookie.Account = user.Name;
                                this.Password = this.ResetPasswork(login, form, this.Site);
                                if (this.Password == null)
                                {
                                    WebServlet.Error(this.Context, "登录异常", String.IsNullOrEmpty(errorMsg) ? String.Format("应用中未发现{1}账户，您可联系{0}应用管理员或使用<a href=\"/UMC.Login/Input\">其他账户</a>登录", this.Site.Caption, this.SiteCookie.Account) : errorMsg);
                                    return true;
                                }
                                autoCheck = true;
                                this.SiteCookie.Model = (this.SiteCookie.Model ?? Entities.AccountModel.Standard) | Entities.AccountModel.Check | Entities.AccountModel.Changed;
                                this.SiteCookie.ChangedTime = 0;
                                break;
                            default:
                                LoginCheckHtml();
                                return true;
                        }
                        break;
                    case Entities.UserModel.Quote:
                        var quoteRoot = this.Site.Site.Account.Substring(1);
                        var home = Data.WebResource.Instance().WebDomain();

                        this.Context.Redirect($"{this.Context.Url.Scheme}://{quoteRoot}.{home}/UMC.Login?callback={Uri.EscapeDataString(this.Context.Url.AbsoluteUri)}");


                        return true;
                    case Entities.UserModel.Share:
                        if (this.ShareUser() == false)
                        {
                            WebServlet.Error(this.Context, "登录异常", String.Format("{0}采用共享账户，但账户却未设置，请联系管理员", this.Site.Caption));

                            return true;
                        }
                        break;
                }
            }

            if (login.ContainsKey("IsLoginHTML") && this.Context.HttpMethod == "GET" && isBody == false)
            {
                LoginHtml("", false);
                return true;
            }
            if (login.ContainsKey("IsNotCookieClear") == false)
            {
                this.Cookies = String.Empty;
            }

            var feildConfig = UMC.Data.JSON.Deserialize<Hashtable>(this.SiteCookie.Config) ?? new Hashtable();
            var lkeyIndex = this.RawUrl.IndexOf('?');
            if (lkeyIndex > 0)
            {
                var qs = System.Web.HttpUtility.ParseQueryString(this.RawUrl.Substring(lkeyIndex));
                for (var i = 0; i < qs.Count; i++)
                {
                    var key = qs.GetKey(i);
                    var value = qs.Get(i);
                    if (String.IsNullOrEmpty(key) == false && String.IsNullOrEmpty(value) == false)
                    {
                        feildConfig[key] = value;

                    }
                }
            }

            if (this.IsLog == true)
                this.Loger.WriteLine("用户登录:");
            NetHttpResponse httpResponse = null;
            try
            {
                // Console.WriteLine("用户登录");
                var isOk = XHR(login, form, feildConfig, "LOGIN", "", out httpResponse);

                // Console.WriteLine("登录完成");
                if (isBody)
                {
                    if (httpResponse.IsReadBody)
                    {
                        this.Header(httpResponse);
                        this.Context.Output.Write(_CheckBody);
                    }
                    else
                    {
                        using (var ms = new System.IO.MemoryStream())
                        {
                            httpResponse.ReadAsStream(ms);
                            ms.Position = 0;

                            this.Header(httpResponse);
                            this.Context.ContentLength = ms.Length;
                            ms.CopyTo(this.Context.OutputStream);

                        }

                    }
                    return true;

                }
                if (isOk)
                {
                    return LoginAfter(feildConfig, form, isHome, login, httpResponse);
                }
                else
                {
                    if (String.IsNullOrEmpty(errorMsg) == false)
                    {
                        WebServlet.Error(this.Context, "登录配置异常", errorMsg);
                        return true;
                    }
                    else if (this.SiteCookie.IndexValue != 0)
                    {
                        LoginHtml("账户或密码不正确", true);
                        return true;
                    }
                    else
                    {
                        switch (this.Site.Site.UserModel ?? Entities.UserModel.Standard)
                        {
                            case Entities.UserModel.Standard:

                                LoginHtml(String.IsNullOrEmpty(errorMsg) ? "账户或密码不正确" : errorMsg, true);
                                return true;
                            case Entities.UserModel.Checked:

                                if (autoCheck)
                                {
                                    WebServlet.Error(this.Context, "登录异常", String.IsNullOrEmpty(errorMsg) ? String.Format("在{0}应用{1}检测账户登录失败，您可联系管理员重置标准账户", this.Site.Caption, user.Name) : errorMsg);
                                    return true;
                                }
                                else
                                {
                                    this.Password = this.ResetPasswork(login, form, this.Site);


                                    if (this.Password == null)
                                    {
                                        WebServlet.Error(this.Context, "登录异常", String.IsNullOrEmpty(errorMsg) ? String.Format("在{0}应用{1}检测账户登录失败，您可联系管理员重置标准账户", this.Site.Caption, user.Name) : errorMsg);
                                        return true;
                                    }
                                    else
                                    {
                                        this.SiteCookie.Account = user.Name;

                                        this.SiteCookie.Model = (this.SiteCookie.Model ?? Entities.AccountModel.Standard) | Entities.AccountModel.Check | Entities.AccountModel.Changed; ;
                                        this.SiteCookie.ChangedTime = 0;

                                        feildConfig = UMC.Data.JSON.Deserialize<Hashtable>(this.SiteCookie.Config) ?? new Hashtable();
                                        httpResponse.ReadAsString();
                                        if (XHR(login, form, feildConfig, "LOGIN", "", out httpResponse))
                                        {
                                            return LoginAfter(feildConfig, form, isHome, login, httpResponse);
                                        }
                                        else
                                        {
                                            WebServlet.Error(this.Context, "登录异常", String.Format("{0}是采用检测密码账户，却不能正常使用，请联系管理员", this.Site.Caption, this.Site.Site.Account.Substring(1)));
                                            return true;
                                        }
                                    }
                                }
                            case Entities.UserModel.Check:

                                var am = this.SiteCookie.Model ?? Entities.AccountModel.Standard;
                                if ((am & Entities.AccountModel.Check) == Entities.AccountModel.Check)
                                {
                                    goto case Entities.UserModel.Checked;
                                }
                                else
                                {
                                    DataFactory.Instance().Delete(this.SiteCookie);
                                    LoginCheckHtml();
                                    return true;
                                }

                            case Entities.UserModel.Quote:
                                var currentTime = UMC.Data.Utility.TimeSpan();
                                var q = UMC.Data.Utility.IntParse(this.Context.Token.Get("DeviceQuote") as string, 0);
                                if (q + 10 > currentTime)
                                {
                                    WebServlet.Error(this.Context, "登录异常", String.Format("{0}是引用账户，多次尝试却没有成功，请联系管理员", this.Site.Caption, this.Site.Site.Account.Substring(1)));
                                    return true;
                                }
                                else
                                {
                                    var quoteRoot = this.Site.Site.Account.Substring(1);
                                    this.Context.Token.Put("DeviceQuote", currentTime.ToString()).Commit(Context.UserHostAddress, Context.Server);
                                    var home = Data.WebResource.Instance().WebDomain();
                                    this.Context.Redirect($"{this.Context.Url.Scheme}://{quoteRoot}.{home}/UMC.Login?callback={Uri.EscapeDataString(this.Context.Url.AbsoluteUri)}");
                                }
                                return true;
                            case Entities.UserModel.Share:

                                if (this.ShareUser() == false)
                                {
                                    WebServlet.Error(this.Context, "登录异常", String.Format("{0}是采用共享账户，却没有设置账户，请联系管理员", this.Site.Caption, this.Site.Site.Account.Substring(1)));
                                    return true;
                                }
                                httpResponse.ReadAsString();
                                feildConfig = UMC.Data.JSON.Deserialize<Hashtable>(this.SiteCookie.Config) ?? new Hashtable();
                                if (XHR(login, form, feildConfig, "LOGIN", "", out httpResponse))
                                {
                                    return LoginAfter(feildConfig, form, isHome, login, httpResponse);
                                }
                                else
                                {
                                    WebServlet.Error(this.Context, "登录异常", String.Format("{0}是采用共享账户，却不能正常使用，请联系管理员", this.Site.Caption, this.Site.Site.Account.Substring(1)));
                                    return true;
                                }
                            default:
                                LoginHtml(String.IsNullOrEmpty(errorMsg) ? "账户或密码不正确" : errorMsg, true);
                                return true;
                        }



                    }
                }
            }
            finally
            {
                httpResponse?.ReadAsString();
            }
        }
        public bool ShareUser()
        {
            var user = this.Site.Site.Account;
            if (String.IsNullOrEmpty(user) == false)
            {

                var vindex = user.IndexOf("~");
                if (vindex > -1)
                {
                    var nv = user.Substring(0, vindex);
                    var fv = user.Substring(vindex + 1);
                    int start = UMC.Data.Utility.IntParse(nv.Substring(nv.Length - fv.Length), -1);
                    int end = UMC.Data.Utility.IntParse(fv, 0);

                    var index = "0000000" + (start + (Data.Reflection.TimeSpanMilli(DateTime.Now) % (end - start + 1)));
                    this.SiteCookie.Account = nv.Substring(0, nv.Length - fv.Length) + index.Substring(index.Length - fv.Length);
                    this.Password = UMC.Data.DataFactory.Instance().Password(SiteConfig.MD5Key(this.Site.Root, this.Site.Site.Account));
                    return true;
                }
                else if (user.IndexOf('|') > 0)
                {
                    var us = user.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
                    this.SiteCookie.Account = us[Data.Reflection.TimeSpanMilli(DateTime.Now) % us.Length];
                    this.Password = UMC.Data.DataFactory.Instance().Password(SiteConfig.MD5Key(this.Site.Root, this.Site.Site.Account));
                    return true;
                }
                else
                {
                    this.SiteCookie.Account = user;
                    this.Password = UMC.Data.DataFactory.Instance().Password(SiteConfig.MD5Key(this.Site.Root, this.Site.Site.Account));
                    return true;
                }
            }
            return false;
        }

        bool LoginAfter(Hashtable fieldConfig, NameValueCollection form, bool isHome, Hashtable loginConfig, NetHttpResponse httpResponse)
        {
            this.IsChangeUser = true;
            var configValue = new Hashtable();
            var fdcem = fieldConfig.GetEnumerator();
            while (fdcem.MoveNext())
            {
                if (fdcem.Key.ToString().StartsWith("_") == false)
                {
                    configValue[fdcem.Key] = fdcem.Value;
                }
            }

            var feilds = loginConfig["Feilds"] as Hashtable;//?? new Hashtable();

            switch (this.Site.Site.UserModel)
            {
                case Entities.UserModel.Share:
                    break;
                default:
                    if (this.Site.Site.IsAuth == true)
                    {
                        var user = this.User;
                        if (String.Equals(this.SiteCookie.Account, user.Name) || String.IsNullOrEmpty(this.SiteCookie.Account))
                        {
                            configValue["__ORGA"] = user.Organizes;
                            configValue["__ROLE"] = String.Join(",", UMC.Data.DataFactory.Instance().Roles(user.Id.Value, this.Site.Site.SiteKey.Value));//.Join(",");
                        }
                        else
                        {
                            var account = Security.Membership.Instance().Identity(this.Site.Site.SiteKey.Value, this.SiteCookie.Account);
                            if (account != null)
                            {
                                configValue["__ALIAS"] = account.Alias;
                                configValue["__ROLE"] = String.Join(",", account.Roles);
                                configValue["__ORGA"] = String.Join(",", account.Organizes);
                            }
                        }

                    }
                    break;
            }
            this.SiteCookie.Config = UMC.Data.JSON.Serialize(configValue);

            var IsLoginHTML = loginConfig.ContainsKey("IsLoginHTML");
            if (IsLoginHTML)
            {
                var script = loginConfig["Script"] as string;
                if (String.IsNullOrEmpty(script) == false && String.Equals(script, "none", StringComparison.CurrentCultureIgnoreCase) == false)
                {
                    var html = httpResponse.IsReadBody ? this._CheckBody : httpResponse.ReadAsString();

                    var values = this.GetKeyValue(html, script);
                    var nvs = (values as Hashtable).GetEnumerator();

                    while (nvs.MoveNext())
                    {
                        fieldConfig[nvs.Key] = nvs.Value;
                    }
                }

            }


            switch (this.Site.Site.UserModel ?? Entities.UserModel.Standard)
            {
                case Entities.UserModel.Check:
                case Entities.UserModel.Checked:
                case Entities.UserModel.Standard:
                    var AccountModel = this.SiteCookie.Model ?? Entities.AccountModel.Standard;

                    var changeTime = (this.SiteCookie.ChangedTime ?? 0) + 3600 * 24 * 100;

                    if (String.Equals(form.Get("AutoUpdatePwd"), "YES"))
                    {

                        this.Update(fieldConfig, form);
                    }
                    else if ((AccountModel & Entities.AccountModel.Changed) == Entities.AccountModel.Changed && changeTime < UMC.Data.Utility.TimeSpan())
                    {
                        this.Update(fieldConfig, form);

                    }
                    break;

            }
            if (String.Equals("/UMC.Login/New", this.RawUrl))
            {
                this.Context.AddHeader("Cache-Control", "no-store");
                this.Context.ContentType = "text/html; charset=UTF-8";
                this.Context.Output.WriteLine("<script>window.top.postMessage(JSON.stringify({ type: 'msg', value: '设置多账户成功，现在你可以打开了' }), '*');");
                this.Context.Output.WriteLine("window.top.postMessage(JSON.stringify({ type: 'close', value: 'close' }), '*');</script>");
                return true;
            }

            if (CheckBrowser() == false)
            {
                return true;

            }
            if (feilds?.ContainsKey("LoginAfter") == true)
            {
                var conf = GetConf($"SITE_MIME_{Site.Root}_LOGIN_LOGINAFTER".ToUpper());

                GetConfig(conf, this.Match(loginConfig, this.SiteCookie.Account, this.Password, ""));
            }
            var a = this.Authority;
            var h = this.Host;

            if (a[0] == '.')
            {
                a = a.Substring(a.IndexOf('.') + 1);
                h = h.Substring(1);
            }
            foreach (var o in this.OuterCookies)
            {
                this.Context.AddHeader("Set-Cookie", Utility.FirstReplace(o, h, a));
            }
            var callbackKey = loginConfig["Callback"] as string ?? "callback";
            var callback = this.Context.QueryString.Get(callbackKey);
            if (String.IsNullOrEmpty(callback) == false)
            {
                this.Context.Redirect(callback);
                return true;
            }


            if (IsLoginHTML)
            {
                var mainKey = String.Format("SITE_MIME_{0}_LOGIN_HTML", this.Site.Root).ToUpper();
                var config = UMC.Data.DataFactory.Instance().Config(mainKey);
                if (config != null && String.Equals(config.ConfValue, "none") == false)
                {
                    this.Isurlencoded = false;
                    this.Context.AddHeader("Cache-Control", "no-store");
                    this.Context.ContentType = "text/html; charset=UTF-8";

                    using (System.IO.Stream stream = typeof(HttpProxy).Assembly
                                                   .GetManifestResourceStream("UMC.ITME.Resources.login-html.html"))
                    {
                        var str = new System.IO.StreamReader(stream).ReadToEnd();
                        var matchEvaluator = Match(fieldConfig, "");
                        this.Context.Output.Write(new System.Text.RegularExpressions.Regex("\\{(?<key>\\w+)\\}").Replace(str, g =>
                        {
                            var key = g.Groups["key"].Value.ToLower();
                            switch (key)
                            {
                                case "title":
                                    return String.Format("{0}账户对接", this.Site.Caption);
                                case "html":
                                    return Regex.Replace(config.ConfValue, matchEvaluator);

                            }
                            return "";

                        }));

                    }
                    return true;
                }
            }

            if (isHome)
            {
                if (String.IsNullOrEmpty(_LoginRedirectLocation) == false)
                {
                    var path = new Uri(this.Context.Url, _LoginRedirectLocation).PathAndQuery;
                    if (IsLoginPath(this.Site, path))
                    {
                        this.Context.Redirect(this.Site.Home ?? "/");
                    }
                    else
                    {
                        this.Context.Redirect(ReplaceRedirect(_LoginRedirectLocation));
                    }
                }
                else
                {
                    this.Context.Redirect(this.Site.Home ?? "/");
                }

            }
            return isHome;

        }

        bool SaveCookie()
        {

            if (this.IsChangeUser == true)
            {
                var siteCookie = new Entities.Cookie
                {
                    Domain = _RootKey,
                    Time = DateTime.Now,
                    user_id = this.SiteCookie.user_id,
                    IndexValue = this.SiteCookie.IndexValue

                };


                var nUP = String.Format("{0}{1}", this.SiteCookie.Account, this.Password);

                if (String.Equals(nUP, this.sourceUP) == false)
                {
                    switch (this.Site.Site.UserModel)
                    {
                        case Entities.UserModel.Quote:

                            if (this.SiteCookie.IndexValue > 0)
                            {
                                UMC.Data.DataFactory.Instance().Password(SiteConfig.MD5Key(Site.Root, siteCookie.user_id.Value, siteCookie.IndexValue ?? 0), this.Password);
                            }
                            break;
                        default:
                            UMC.Data.DataFactory.Instance().Password(SiteConfig.MD5Key(Site.Root, siteCookie.user_id.Value, siteCookie.IndexValue ?? 0), this.Password);

                            break;
                    }
                    siteCookie.Account = this.SiteCookie.Account;
                    siteCookie.ChangedTime = UMC.Data.Utility.TimeSpan();
                    siteCookie.Model = this.SiteCookie.Model;
                    this.sourceUP = nUP;
                }

                siteCookie.Config = this.SiteCookie.Config;
                siteCookie.LoginTime = UMC.Data.Utility.TimeSpan();
                this.IsChangeUser = null;
                DataFactory.Instance().Put(siteCookie);
                return true;

            }

            return false;
        }


        public static void LogWrite(NetContext context, SiteConfig config, int statusCode, String pathAndQuery, string account, int duration, NameValueCollection reHeaders, String attachmentFile)
        {
            var logSetting = LogSetting.Instance();
            if (logSetting.IsWriter)
            {
                var webMeta = new WebMeta();
                if (String.IsNullOrEmpty(account) == false)
                {
                    webMeta.Put("Account", account);
                }
                var time = (int)((UMC.Data.Reflection.TimeSpanMilli(DateTime.Now) - duration) / 1000);
                if (context.UrlReferrer != null)
                {
                    webMeta.Put("Referrer", context.UrlReferrer.AbsoluteUri);
                }
                if (String.IsNullOrEmpty(attachmentFile) == false)
                {
                    webMeta.Put("Attachment", attachmentFile);
                }
                foreach (var u in config.LogConf.Cookies)
                {
                    webMeta[u] = context.Cookies[u];
                }

                foreach (var u in config.LogConf.Headers)
                {
                    webMeta[u] = context.Headers[u];
                }
                if (reHeaders != null)
                {
                    foreach (var u in config.LogConf.ResHeaders)
                    {
                        webMeta[u] = reHeaders[u];
                    }
                }

                if (context.Token != null)
                {
                    var username = context.Token.Username;
                    if (String.IsNullOrEmpty(username) || String.Equals(username, "?"))
                    {
                        username = $"G:{UMC.Data.Utility.IntParse((context.Token.UserId ?? context.Token.Device).Value)}";
                    }
                    webMeta.Put("Username", username);
                }
                webMeta.Put("Address", context.UserHostAddress).Put("Server", context.Server).Put("UserAgent", context.UserAgent)
                .Put("Path", pathAndQuery)
                .Put("Duration", duration)
                .Put("Site", config.Root)
                .Put("Time", time)
                .Put("Status", statusCode);

                logSetting.Write(webMeta);
            }

        }
        NameValueCollection m_HttpHeaders;
        String _AttachmentFile;

        void Header(NetHttpResponse httpResponse, bool isContentEncoding, bool isCache)
        {
            _AttachmentFile = httpResponse.AttachmentFile;
            m_HttpHeaders = httpResponse.Headers;
            var statusCode = Convert.ToInt32(httpResponse.StatusCode);
            this.Context.StatusCode = statusCode;
            var headerCheck = new SiteConfig.PageConfig<SiteConfig.ReplaceSetting> { EndPath = String.Empty };


            headerCheck.StartPath = "Redirect";
            SiteConfig.PageConfig<SiteConfig.ReplaceSetting> _Redirect, _Cookie;

            this.Site.HostPage.TryGetValue(headerCheck, out _Redirect);

            headerCheck.StartPath = "Set-Cookie";
            this.Site.HostPage.TryGetValue(headerCheck, out _Cookie);
            var sb = new StringBuilder();

            for (var i = 0; i < m_HttpHeaders.Count; i++)
            {
                var key = m_HttpHeaders.GetKey(i);

                switch (key.ToLower())
                {
                    case "set-cookie":
                        var vs = m_HttpHeaders.GetValues(i);

                        foreach (var k in vs)
                        {
                            var kname = k.Substring(0, k.IndexOf('=') + 1);
                            this.OuterCookies.RemoveAll(r => r.StartsWith(kname));
                            sb.Clear();
                            this.OutputReplace(sb, k, _Cookie?.Value);
                            this.Context.AddHeader(key, sb.ToString());
                        }

                        break;
                    case "content-encoding":
                        if (isContentEncoding)
                        {
                            this.Context.AddHeader(key, m_HttpHeaders.Get(i));
                        }
                        break;
                    case "location":

                        sb.Clear();
                        this.OutputReplace(sb, m_HttpHeaders.Get(i), _Redirect?.Value);
                        this.Context.AddHeader(key, sb.ToString());
                        break;
                    case "access-control-allow-origin":
                        // var value = m_HttpHeaders.Get(i);
                        // if (value == "*")
                        // {
                        //     this.Context.AddHeader(key, "*");
                        // }
                        // else
                        // {
                        this.Context.AddHeader(key, this.Context.Headers.Get("Origin") ?? m_HttpHeaders.Get(i));
                        // }
                        break;
                    case "strict-transport-security":
                    case "content-type":
                    case "server":
                    case "connection":
                    case "keep-alive":
                        break;
                    case "content-length":
                    case "transfer-encoding":
                        if (httpResponse.IsHead)
                        {
                            this.Context.AddHeader(key, m_HttpHeaders.Get(i));
                        }
                        break;

                    case "last-modified":
                    case "etag":
                        if (isCache)
                        {
                            this.Context.AddHeader(key, m_HttpHeaders.Get(i));
                        }
                        break;
                    default:
                        headerCheck.StartPath = key;
                        if (this.Site.HostPage.TryGetValue(headerCheck, out var check))
                        {
                            sb.Clear();
                            this.OutputReplace(sb, m_HttpHeaders.Get(i), check.Value);
                            this.Context.AddHeader(key, sb.ToString());
                        }
                        else
                        {
                            this.Context.AddHeader(key, m_HttpHeaders.Get(i));
                        }
                        break;
                }
            }
            foreach (var o in this.OuterCookies)
            {
                sb.Clear();
                this.OutputReplace(sb, o, _Cookie?.Value);
                this.Context.AddHeader("Set-Cookie", sb.ToString());
            }
            var ContentType = httpResponse.ContentType;

            if (String.IsNullOrEmpty(ContentType) == false)
            {
                this.Context.ContentType = ContentType;
            }
            else if (httpResponse.StatusCode == HttpStatusCode.OK)
            {
                this.Context.ContentType = this.Site.ContentType;
            }
        }
        void Header(NetHttpResponse httpResponse)
        {
            Header(httpResponse, true, true);
        }
        public void Response(NetHttpResponse httpResponse)
        {
            if (httpResponse.IsHead)
            {
                Header(httpResponse);
            }
            else
            {
                var ContentType = httpResponse.ContentType;
                var ContentEncoding = httpResponse.ContentEncoding;
                SiteConfig.ReplaceSetting replaceSetting = null;
                string jsAppendKey = null;
                int model = 0;
                if (String.IsNullOrEmpty(ContentType) == false)
                {
                    var vIndex = ContentType.IndexOf(';');
                    if (vIndex > 0)
                    {
                        ContentType = ContentType.Substring(0, vIndex);
                    }
                    if (String.Equals(ContentType, "text/html", StringComparison.CurrentCultureIgnoreCase))
                    {
                        if (CheckPath(this.Path, out jsAppendKey, this.Site.AppendJSConf))
                        {
                            model = 1;
                        }
                        if (this.CheckPath(this.Path, ContentType, out replaceSetting))
                        {
                            if (replaceSetting.Model != SiteConfig.HostReplaceModel.Input)
                            {
                                model = 1;
                            }
                        }

                    }
                    else if (this.CheckPath(this.Path, ContentType, out replaceSetting))
                    {
                        model = 2;
                    }

                }
                switch (model)
                {
                    case 1:
                    case 2:
                        Header(httpResponse, false, true);
                        if (String.IsNullOrEmpty(httpResponse.ContentEncoding))
                        {
                            var stream = new DeflateStream(this.Context.OutputStream, CompressionMode.Compress);

                            this.Context.AddHeader("Content-Encoding", "deflate");
                            var replacer = new Replacer(this, stream.Write, replaceSetting, 1, 0, 0, jsAppendKey);

                            httpResponse.ReadAsData((b, i, c) =>
                            {
                                if (c == 0 && b.Length == 0)
                                {
                                    if (i == -1)
                                    {
                                        this.Context.Error(httpResponse.Error);
                                    }
                                    else
                                    {
                                        replacer.Flush();
                                        stream.Flush();
                                        this.Context.OutputFinish();
                                    }
                                }
                                else
                                {
                                    replacer.Replace((buffer, offset, size) =>
                                    {
                                        if (c == 0)
                                        {
                                            return 0;
                                        }

                                        Array.Copy(b, i, buffer, offset, 1);
                                        i++;
                                        c--;
                                        return 1;
                                    });
                                }
                            });
                        }
                        else
                        {
                            httpResponse.ReadAsStream(content =>
                            {
                                content.Position = 0;
                                switch (model)
                                {
                                    case 1:
                                        this.OuterHTML(content, replaceSetting, ContentEncoding, this.Context.OutputStream, true, jsAppendKey);
                                        break;
                                    default:
                                        this.OuterReplaceHost(content, ContentEncoding, replaceSetting, this.Context.OutputStream, true);
                                        break;
                                }
                                this.Context.OutputFinish();
                                content.Close();
                            }, this.Context.Error);
                        }
                        return;
                    default:
                        Header(httpResponse);
                        break;
                }
            }


            if (httpResponse.ContentLength > -1)
            {
                this.Context.ContentLength = httpResponse.ContentLength;

            }

            httpResponse.ReadAsData((b, i, c) =>
            {
                if (c == 0 && b.Length == 0)
                {
                    if (i == -1)
                    {
                        this.Context.Error(httpResponse.Error);
                    }
                    else
                    {
                        this.Context.OutputFinish();
                    }
                }
                else
                {
                    this.Context.OutputStream.Write(b, i, c);
                }
            });


        }
        UMC.Security.Identity User;
        long StartTime;

        public void ProcessEnd()
        {

            LogWrite(this.Context, this.Site, this.Context.StatusCode, String.Format("{0} {1}", Context.HttpMethod, this.RawUrl), this.SiteCookie.Account, (int)(UMC.Data.Reflection.TimeSpanMilli(DateTime.Now) - StartTime), m_HttpHeaders, _AttachmentFile);

            this.SaveCookie();
            if (this.IsLog && User.IsAuthenticated)
            {

                var file = UMC.Data.Reflection.ConfigPath(String.Format("Static\\log\\{0}\\{1}.log", Site.Root, User.Name));
                if (!System.IO.Directory.Exists(System.IO.Path.GetDirectoryName(file)))
                {
                    System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(file));
                }
                using (FileStream stream = new FileStream(file, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
                {
                    var writer = new System.IO.StreamWriter(stream);
                    writer.Write(this.Loger.ToString());
                    writer.Flush();
                    writer.Close();
                }
            }

            this.Loger.Close();
        }
        public void AuthBridge()
        {

            var user = this.User;
            switch (this.Site.Site.UserModel)
            {
                case Entities.UserModel.Share:
                    break;
                default:
                    if (this.Site.Site.IsAuth == true)
                    {
                        user = this.Account;
                    }
                    break;
            }
            this.Context.Headers.Add("umc-request-user-name", Uri.EscapeDataString(user.Name));
            this.Context.Headers.Add("umc-request-user-id", UMC.Data.Utility.Guid(user.Id.Value));

            if (String.IsNullOrEmpty(user.Alias) == false)
            {
                this.Context.Headers.Add("umc-request-user-alias", Uri.EscapeDataString(user.Alias));
            }
            if (user.Roles.Length > 0)
            {
                this.Context.Headers.Add("umc-request-user-roles", Uri.EscapeDataString(String.Join(",", user.Roles)));
            }

            if (user.Organizes.Length > 0)
            {
                this.Context.Headers.Add("umc-request-user-organizes", Uri.EscapeDataString(String.Join(",", user.Organizes)));
            }

            if (String.IsNullOrEmpty(Site.Site.AppSecret) == false)
            {
                this.Context.Headers.Add("umc-request-time", Utility.TimeSpan().ToString());
                this.Context.Headers.Add("umc-request-sign", Utility.Sign(this.Context.Headers, "umc-", Site.Site.AppSecret));
            }

        }

        public void LoginRequest()
        {
            this.Context.UseSynchronousIO(this.ProcessEnd);
            this.Context.ReadAsForm(this.LoginEnd);
        }
        void ClearCookie(string domain)
        {
            var cCookes = this.Site.Cookies;
            if (String.IsNullOrEmpty(domain) == false && this.Site.SubCookies.TryGetValue(domain, out cCookes) == false)
            {
                cCookes = this.Site.Cookies;
            }
            if (cCookes.Count == 0)
            {
                var ms = this.Context.Cookies;
                for (var i = 0; i < ms.Count; i++)
                {
                    var name = ms.GetKey(i);
                    var value = ms.Get(i);
                    switch (name)
                    {
                        case DeviceIndex:
                        case Web.WebServlet.SessionCookieName:
                            break;
                        default:
                            this.OuterCookies.Add($"{name}=; Expires={DateTime.Now.AddDays(-1).ToString("r")}; HttpOnly; Path=/");
                            break;
                    }
                }
                this.Cookies = String.Empty;
            }
            else
            {

                var em = cCookes.GetEnumerator();
                while (em.MoveNext())
                {
                    this.OuterCookies.Add($"{em.Current.Key}=; Expires={DateTime.Now.AddDays(-1).ToString("r")}; HttpOnly; Path={em.Current.Value}");
                }
                var sb = new StringBuilder();
                var ms = this.Context.Cookies;
                for (var i = 0; i < ms.Count; i++)
                {
                    var name = ms.GetKey(i);
                    var value = ms.Get(i);
                    switch (name)
                    {
                        case DeviceIndex:
                        case Web.WebServlet.SessionCookieName:
                            break;
                        default:
                            if (cCookes.TryGetValue(name, out var path) == false)
                            {
                                if (sb.Length > 0)
                                {
                                    sb.Append("; ");
                                }
                                sb.Append(name);
                                sb.Append("=");
                                sb.Append(value);
                            }
                            break;
                    }
                }
                this.Cookies = sb.ToString();
            }
        }
        void LoginEnd(NameValueCollection form)
        {
            try
            {
                Login(form);
            }
            finally
            {
                this.Context.OutputFinish();
            }
        }

        void Login(NameValueCollection form)
        {

            var apis = this.Context.Url.AbsolutePath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
            if (apis.Length == 1)
            {
                this.Context.AddHeader("Set-Cookie", $"{DeviceIndex}=; Expires={DateTime.Now.AddDays(-10).ToString("r")}; HttpOnly; Path=/");


                if (this.Site.Site.UserModel == Entities.UserModel.Bridge)
                {
                    this.Context.Redirect(this.Site.Site.Home ?? "/");
                }
                else if (CheckAccountSelectHtml() == false)
                {
                    this.Context.Redirect("/UMC.Login/Go" + this.Context.Url.Query);
                }

                return;
            }
            var lv = apis[1];

            switch (lv)
            {
                case "Out":
                    this.Login(true, true, form, String.Empty);
                    return;
                case "Check":
                    if (Site.Site.AuthType >= WebAuthType.User)
                    {
                        if (this.SiteCookie.Time.HasValue)
                        {
                            var authExpire = this.Site.Site.AuthExpire ?? 30;
                            if (authExpire > 0 && this.SiteCookie.Time.Value.AddMinutes(authExpire) < DateTime.Now)
                            {
                                this.Context.Redirect("/UMC.Login/Go" + this.Context.Url.Query);
                            }
                            else
                            {
                                var callback = this.Context.QueryString.Get("callback");
                                if (String.IsNullOrEmpty(callback))
                                {
                                    this.Context.Redirect(callback);
                                }
                                else if (String.IsNullOrEmpty(this.Site.Site.Home))
                                {
                                    this.Context.Redirect("/");
                                }
                                else
                                {
                                    this.Context.Redirect(this.Site.Site.Home);
                                }
                            }
                        }
                        else
                        {
                            this.Context.Redirect("/UMC.Login/Go" + this.Context.Url.Query);
                        }
                    }
                    break;
                case "Auto":
                case "Input":
                case "Go":
                    this.Login(true, false, form, lv);
                    return;
                case "New":
                    var scookies = DataFactory.Instance().Cookies(this.Site.Root, User.Id.Value).OrderBy(r => r.IndexValue).ToList();

                    foreach (var sc in scookies)
                    {
                        if (String.IsNullOrEmpty(sc.Account))
                        {
                            this.SiteCookie = sc;

                            break;
                        }
                    }
                    this.Cookies = String.Empty; //new CookieContainer();
                    this.Login(true, false, form, String.Empty);
                    return;
                default:
                    if (Utility.IntParse(lv, -1) > -1)
                    {
                        ClearCookie(String.Empty);

                        if (String.Equals(lv, "0") == false)
                        {
                            this.Context.AddHeader("Set-Cookie", $"{DeviceIndex}={lv}; HttpOnly; Path=/");

                        }
                        else
                        {
                            this.Context.AddHeader("Set-Cookie", $"{DeviceIndex}=; Expires={DateTime.Now.AddYears(-10).ToString("r")}; HttpOnly; Path=/");
                        }

                        foreach (var o in this.OuterCookies)
                        {
                            this.Context.AddHeader("Set-Cookie", o);
                        }

                        this.Context.Redirect("/UMC.Login/Go");
                        return;
                    }
                    break;
            }
            var login = GetConf(String.Format("SITE_MIME_{0}_LOGIN_{1}", Site.Root, lv).ToUpper());
            if (login != null && login.Count > 0)
            {
                this.Password = UMC.Data.DataFactory.Instance().Password(SiteConfig.MD5Key(this.Site.Root, this.SiteCookie.user_id.Value, 0));
                var hash = new Hashtable();
                UMC.Data.Utility.AppendDictionary(hash, form);
                var usernmae = hash["Username"] as string;
                hash.Remove("Username");
                this.Context.ContentType = "application/json; charset=utf-8";
                var json = GetConfig(login, this.Match(hash, usernmae ?? this.SiteCookie.Account, this.Password, ""));
                if (String.Equals("[]", json) || String.Equals("{}", json))
                {
                    if (login.Contains("DefautValue"))
                    {
                        var DefautValue = login["DefautValue"] as string;
                        if (String.IsNullOrEmpty(DefautValue) == false)
                        {
                            var sKey = SiteConfig.Config(DefautValue);
                            switch (sKey.Length)
                            {
                                case 0:
                                    break;
                                case 1:
                                    json = UMC.Data.JSON.Serialize(new WebMeta[] { new WebMeta().Put("Text", sKey[0], "Value", sKey[0]) });
                                    break;
                                default:
                                    var ls = new List<WebMeta>();
                                    int l = sKey.Length / 2;
                                    for (var i = 0; i < l; i++)
                                    {
                                        ls.Add(new WebMeta().Put("Text", sKey[0], "Value", sKey[1]));
                                    }
                                    json = UMC.Data.JSON.Serialize(ls);

                                    break;
                            }
                        }
                    }
                }

                this.Context.Output.Write(json);
            }
            else
            {
                var hash = new Hashtable();
                UMC.Data.Utility.AppendDictionary(hash, this.Context.QueryString);
                lv = this.Context.QueryString.Get("$");
                hash.Remove("$");
                if (String.IsNullOrEmpty(lv) == false)
                {
                    this.Isurlencoded = false;
                    this.Context.ContentType = "application/json; charset=utf-8";
                    this.Context.Output.Write(Regex.Replace(lv, this.Match(hash, "", "", "")));

                }
            }
        }
        string _RootKey;
        public void ProcessRequest()
        {

            if (this.StaticModel != 0 && this.Site.Site.UserModel == Entities.UserModel.Bridge)
            {

                this.AuthBridge();

            }
            // var getUrl = new Uri(Domain, RawUrl);

            this.Context.UseSynchronousIO(this.ProcessEnd);
            switch (Context.HttpMethod)
            {
                case "OPTIONS":
                    {
                        var webReq = this.Reqesut(this.Context.Transfer(Domain));
                        webReq.RawUrl = RawUrl;
                        webReq.Net(this.Context, (xhr) =>
                        {
                            xhr.Headers["Access-Control-Allow-Credentials"] = "true";
                            this.Response(xhr);
                        });
                    }
                    break;
                default:
                    {

                        var webReq = this.Reqesut(this.Context.Transfer(Domain));

                        webReq.RawUrl = RawUrl;
                        // SiteConfig.ReplaceSetting replaceSetting;
                        if (this.CheckPath(this.Path, this.Context.ContentType, out var replaceSetting))
                        {

                            if ((replaceSetting.Model & SiteConfig.HostReplaceModel.Input) == SiteConfig.HostReplaceModel.Input && (this.Context.ContentLength ?? 0) > 0)
                            {
                                var ms = NetClient.TempStream();
                                var replacer = new Replacer(this, ms.Write, replaceSetting, 0, 2, 3, String.Empty);
                                this.Context.ReadAsData(new UMC.Net.DataReader((b, i, c) =>
                                {

                                    replacer.Replace((buffer, offset, size) =>
                                    {
                                        if (c == 0)
                                        {
                                            return 0;
                                        }

                                        Array.Copy(b, i, buffer, offset, 1);
                                        i++;
                                        c--;
                                        return 1;
                                    });
                                }, e =>
                                {
                                    replacer.Flush();
                                    ms.Flush();
                                    ms.Position = 0;
                                    webReq.ContentType = this.Context.ContentType;
                                    webReq.Net(this.Context.HttpMethod, ms, ms.Length, r =>
                                    {
                                        ms.Close();
                                        ms.Dispose();
                                        this.Response(r);
                                    });
                                }, e =>
                                {
                                    this.Context.Error(e ?? new WebException("接收Body错误"));
                                }).Write);
                            }
                            else
                            {
                                webReq.Net(this.Context, this.Response);
                            }
                        }
                        else
                        {
                            webReq.Net(this.Context, this.Response);

                        }
                        if (this.IsLog == true)
                        {
                            this.Loger.Write(this.Context.HttpMethod);
                            this.Loger.Write(":");
                            this.Loger.WriteLine(this.RawUrl);
                            this.Loger.WriteLine(System.Text.UTF8Encoding.UTF8.GetString(webReq.Headers.ToByteArray()));

                        }
                    }
                    break;
                case "GET":
                    {
                        if (IsLoginPath(this.Site, this.RawUrl, out var _go))
                        {
                            if (_go)
                            {
                                if (this.Login(false, false, new NameValueCollection(), String.Empty))
                                {
                                    this.Context.OutputFinish();
                                }
                                else
                                {
                                    Get();
                                }
                            }
                            else
                            {
                                var urlReferrer = this.Context.UrlReferrer;
                                if (urlReferrer == null || String.Equals(this.Context.Url.Host, urlReferrer.Host) == false)
                                {
                                    this.Context.Redirect("/UMC.Login");
                                }
                                else
                                {
                                    SignOutHtml();
                                }
                                this.Context.OutputFinish();
                            }
                        }
                        else
                        {
                            Get();
                        }
                    }
                    break;
            }
        }
        void Get()
        {
            var IsCache = false;

            string filename = String.Empty;

            if (this.StaticModel >= 0)
            {
                var pmd5Key = $"{this.Site.Site.Version}{_RootKey}{WebServlet.MainDomain}";
                switch (this.StaticModel)
                {
                    case 0:
                        break;
                    case 1:
                        break;
                    case 2:
                        pmd5Key = $"{pmd5Key}{this.SiteCookie.Account}";
                        break;
                    default:
                        pmd5Key = String.Format("{0}_{1}_{2}", this.SiteCookie.Account, UMC.Data.Utility.TimeSpan() / 60 / this.StaticModel, pmd5Key);
                        break;
                }
                if (IsTest == false)
                {
                    IsCache = true;
                    if (this.Context.CheckCache(Site.Root, pmd5Key, out filename))
                    {
                        this.Context.OutputFinish();
                        return;
                    }
                }
            }
            var webr = this.Reqesut(Context.Transfer(this.Domain));

            webr.RawUrl = RawUrl;
            webr.Get(httpResponse =>
              {
                  var statusCode = Convert.ToInt32(httpResponse.StatusCode);

                  this.Context.StatusCode = statusCode;
                  var contentType = httpResponse.ContentType ?? String.Empty;

                  if (String.IsNullOrEmpty(contentType) == false)
                  {
                      this.Context.ContentType = contentType;
                  }
                  else if (httpResponse.StatusCode == HttpStatusCode.OK)
                  {
                      this.Context.ContentType = Site.ContentType;
                  }

                  var ContentType = contentType.Split(';')[0];
                  String jsAppendKey = null;
                  SiteConfig.ReplaceSetting replaceSetting = null;
                  WebMeta ImageConfig = null;
                  int model = 0;
                  if (String.Equals(ContentType, "text/html", StringComparison.CurrentCultureIgnoreCase))
                  {
                      if (CheckPath(this.Path, out jsAppendKey, this.Site.AppendJSConf))
                      {
                          model = 1;
                      }
                      if (this.CheckPath(this.Path, ContentType, out replaceSetting))
                      {
                          if (replaceSetting.Model != SiteConfig.HostReplaceModel.Input)
                          {
                              model = 1;
                          }
                      }

                  }
                  else if (CheckPath(this.Path, out jsAppendKey, this.Site.AppendJSConf))
                  {
                      model = 2;
                  }
                  else if (this.CheckPath(this.Path, ContentType, out replaceSetting))
                  {
                      if ((replaceSetting.Model & SiteConfig.HostReplaceModel.Replace) == SiteConfig.HostReplaceModel.Replace)
                      {
                          model = 3;
                      }
                  }
                  else if (ContentType.StartsWith("image/") && ContentType.Contains("svg") == false)
                  {
                      var ckey = Context.QueryString.Get("umc-image");
                      if (String.IsNullOrEmpty(ckey))
                      {
                          CheckPath(this.Path, ContentType, out ckey, this.Site.ImagesConf);
                      }
                      if (TryImageConfig(this.Site.Root, ckey, out ImageConfig))
                      {
                          var format = ImageConfig["Format"] ?? "Src";
                          if (String.Equals(format, "Src") == false)
                          {
                              ContentType = "image/" + format;
                          }
                          model = 4;
                      }
                  }
                  if (IsCache)
                  {
                      if (String.Equals(httpResponse.Headers.Get("Cache-Control"), "no-store"))
                      {
                          IsCache = false;
                      }
                  }
                  if (httpResponse.StatusCode == HttpStatusCode.OK && IsCache)
                  {
                      switch (model)
                      {
                          case 1:
                          case 2:
                          case 3:
                          case 4:
                              {
                                  var tempFile = System.IO.Path.GetTempFileName();
                                  var etag = Utility.TimeSpan();
                                  var cacheStream = NetClient.MimeStream(tempFile, ContentType, etag);
                                  Header(httpResponse, false, false);

                                  httpResponse.ReadAsStream(content =>
                                  {
                                      content.Position = 0;

                                      switch (model)
                                      {
                                          case 1:
                                              this.OuterHTML(content, replaceSetting, httpResponse.ContentEncoding, cacheStream, false, jsAppendKey);
                                              break;
                                          case 2:
                                              this.OutputAppendJS(content, httpResponse.ContentEncoding, MD5(jsAppendKey, String.Empty), cacheStream);
                                              break;
                                          case 3:
                                              this.OuterReplaceHost(content, httpResponse.ContentEncoding, replaceSetting, cacheStream, false);
                                              break;
                                          case 4:
                                              SiteImage.Convert(content, cacheStream, ImageConfig, filename);
                                              break;
                                      }
                                      content.Dispose();
                                      cacheStream.Flush();
                                      cacheStream.Position = 0;
                                      //   cacheStream.Close();
                                      //   using (var fileStream = System.IO.File.OpenRead(filename))
                                      //   {
                                      this.Context.OutputCache(cacheStream, filename);

                                      this.Context.OutputFinish();
                                      UMC.Data.Utility.Move(tempFile, filename);



                                  }, e =>
                                  {
                                      cacheStream.Close();
                                      DeleteCache(tempFile);
                                      this.Context.Error(e);
                                  });
                              }
                              break;
                          default:
                              {
                                  var tempFile = File.Open(System.IO.Path.GetTempFileName(), FileMode.Create);
                                  Header(httpResponse, true, false);
                                  var tag = Utility.TimeSpan();
                                  this.Context.AddHeader("ETag", tag.ToString());

                                  if (httpResponse.ContentLength > -1)
                                  {
                                      this.Context.ContentLength = httpResponse.ContentLength;
                                  }

                                  httpResponse.ReadAsData(new DataReader((b, i, c) =>
                                  {
                                      tempFile.Write(b, i, c);
                                      this.Context.OutputStream.Write(b, i, c);

                                  }, v =>
                                  {
                                      this.Context.OutputFinish();
                                      tempFile.Flush();

                                      tempFile.Position = 0;
                                      using (var tem = DataFactory.Instance().Decompress(tempFile, httpResponse.ContentEncoding))
                                      {
                                          var tFile = System.IO.Path.GetTempFileName();
                                          var cacheStream = NetClient.MimeStream(tFile, ContentType, tag);
                                          tem.CopyTo(cacheStream);
                                          tempFile.Close();
                                          cacheStream.Close();
                                          Utility.Move(tFile, filename);
                                      }

                                  }, ex =>
                                  {
                                      tempFile.Close();
                                      this.Context.Error(ex ?? httpResponse.Error);

                                  }).Write);
                              }
                              break;
                      }
                      return;

                  }
                  else
                  {
                      switch (model)
                      {
                          case 4:
                          case 2:
                              Header(httpResponse, false, false);
                              httpResponse.ReadAsStream(content =>
                                 {

                                     content.Position = 0;
                                     switch (model)
                                     {
                                         case 2:
                                             this.OutputAppendJS(content, httpResponse.ContentEncoding, MD5(jsAppendKey, ""), this.Context.OutputStream);
                                             break;
                                         case 4:

                                             if (ContentType.Contains("Optimal"))
                                             {
                                                 this.Context.ContentType = "image/webp";
                                             }
                                             SiteImage.Convert(content, this.Context.OutputStream, ImageConfig, String.Empty);
                                             break;
                                     }
                                     this.OutputAppendJS(content, httpResponse.ContentEncoding, MD5(jsAppendKey, String.Empty), this.Context.OutputStream);

                                     this.Context.OutputFinish();

                                 }, this.Context.Error);
                              break;
                          case 1:
                          case 3:

                              Header(httpResponse, false, false);
                              if (String.IsNullOrEmpty(httpResponse.ContentEncoding))
                              {
                                  var stream = new DeflateStream(this.Context.OutputStream, CompressionMode.Compress);

                                  this.Context.AddHeader("Content-Encoding", "deflate");
                                  var replacer = new Replacer(this, stream.Write, replaceSetting, 1, 0, 0, jsAppendKey);

                                  httpResponse.ReadAsData(new UMC.Net.DataReader((b, i, c) =>
                                  {
                                      replacer.Replace((buffer, offset, size) =>
                                          {
                                              if (c == 0)
                                              {
                                                  return 0;
                                              }

                                              Array.Copy(b, i, buffer, offset, 1);
                                              i++;
                                              c--;
                                              return 1;
                                          });
                                  }, e =>
                                  {
                                      replacer.Flush();
                                      stream.Flush();
                                      this.Context.OutputFinish();
                                  }, this.Context.Error).Write);
                              }
                              else
                              {
                                  httpResponse.ReadAsStream(content =>
                                  {
                                      content.Position = 0;

                                      switch (model)
                                      {
                                          case 1:
                                              this.OuterHTML(content, replaceSetting, httpResponse.ContentEncoding, this.Context.OutputStream, true, jsAppendKey);
                                              break;
                                          case 3:
                                              this.OuterReplaceHost(content, httpResponse.ContentEncoding, replaceSetting, this.Context.OutputStream, true);
                                              break;
                                      }
                                      this.Context.OutputFinish();

                                  }, this.Context.Error);
                              }

                              return;
                          default:
                              Header(httpResponse);
                              break;

                      }
                  }

                  if (httpResponse.ContentLength > -1)
                  {
                      this.Context.ContentLength = httpResponse.ContentLength;
                  }
                  httpResponse.ReadAsData((b, i, c) =>
                  {
                      if (c == 0 && b.Length == 0)
                      {
                          if (i == -1)
                          {
                              this.Context.Error(httpResponse.Error);
                          }
                          else
                          {
                              this.Context.OutputFinish();
                          }
                      }
                      else
                      {
                          this.Context.OutputStream.Write(b, i, c);
                      }
                  });
              });

            if (this.IsLog == true)
            {
                this.Loger.Write(this.Context.HttpMethod);
                this.Loger.Write(":");
                this.Loger.WriteLine(this.RawUrl);
                this.Loger.WriteLine(System.Text.UTF8Encoding.UTF8.GetString(webr.Headers.ToByteArray()));

            }

        }
        bool CheckBrowser()
        {
            var uB = Site.Site.UserBrowser ?? Entities.UserBrowser.All;
            var cilentB = Entities.UserBrowser.All;
            var us = this.Context.UserAgent;
            if (uB == Entities.UserBrowser.All)
            {
                return true;

            }
            else if (String.IsNullOrEmpty(us) == false)
            {
                us = us.ToUpper();
                if (us.Contains("CHROME"))
                {
                    cilentB = Entities.UserBrowser.Chrome;
                }
                else if (us.Contains("FIREFOX"))
                {
                    cilentB = Entities.UserBrowser.Firefox;
                }
                else if (us.Contains("MSIE"))
                {
                    cilentB = Entities.UserBrowser.IE;
                }
                else if (us.Contains("DINGTALK"))
                {
                    cilentB = Entities.UserBrowser.Dingtalk;
                }
                else if (us.Contains("WXWORK") || us.Contains("MICROMESSENGER"))
                {
                    cilentB = Entities.UserBrowser.WeiXin;
                }
                else if (us.Contains("WEBKIT"))
                {
                    cilentB = Entities.UserBrowser.WebKit;
                }
                if ((uB & cilentB) != cilentB)
                {
                    var ts = UMC.Data.Utility.Enum(uB);

                    var sb = new List<String>();
                    foreach (var k in ts)
                    {
                        switch (k)
                        {
                            case Entities.UserBrowser.Chrome:
                                sb.Add("谷歌");
                                break;
                            case Entities.UserBrowser.IE:
                                sb.Add("IE");
                                break;
                            case Entities.UserBrowser.Firefox:
                                sb.Add("火狐");
                                break;
                            case Entities.UserBrowser.WebKit:
                                sb.Add("WebKit");
                                break;
                            case Entities.UserBrowser.Dingtalk:
                                sb.Add("钉钉");
                                break;
                            case Entities.UserBrowser.WeiXin:
                                sb.Add("微信");
                                break;
                        }
                    }

                    this.Context.AddHeader("Cache-Control", "no-store");
                    this.Context.ContentType = "text/html; charset=UTF-8";
                    using (System.IO.Stream stream = typeof(HttpProxy).Assembly
                                                          .GetManifestResourceStream("UMC.ITME.Resources.check.html"))
                    {

                        var str = new System.IO.StreamReader(stream).ReadToEnd();
                        this.Context.Output.Write(new System.Text.RegularExpressions.Regex("\\{(?<key>\\w+)\\}").Replace(str, g =>
                        {
                            var key = g.Groups["key"].Value.ToLower();
                            switch (key)
                            {
                                case "authurl":
                                    return new Uri(this.Context.Url, String.Format("/!/{0}/UMC.Login", Utility.MD5(this.Context.Token.Device.Value))).AbsoluteUri;

                                case "authkey":
                                    return "/UMC?_mode=Proxy&_cmd=Auth";

                                case "isie":
                                    return uB == Entities.UserBrowser.IE ? "yes" : "no";

                                case "desc":
                                    return String.Format("{0}只支持在{1}中使用", Site.Caption, String.Join(",", sb.ToArray()));
                            }
                            return "";

                        }));

                    }
                    return false;
                }
            }
            return true;
        }
        static bool IsLoginPath(SiteConfig config, String rawUrl, out bool isGo)
        {
            isGo = false;
            foreach (var path in config.LogoutPath)
            {
                if (path.StartsWith('@'))
                {
                    switch (path[path.Length - 1])
                    {
                        case '$':
                            if (rawUrl.EndsWith(path, 1, path.Length - 2))
                            {
                                isGo = true;
                                return true;
                            }
                            break;
                        case '*':
                            if (rawUrl.StartsWith(path, 1, path.Length - 2))
                            {
                                isGo = true;
                                return true;
                            }
                            break;
                        default:
                            if (rawUrl.EqualsWith(path, 1, path.Length - 1))
                            {
                                isGo = true;
                                return true;
                            }
                            break;
                    }
                }
                else
                {
                    switch (path[path.Length - 1])
                    {
                        case '$':
                            if (rawUrl.EndsWith(path, 0, path.Length - 1))
                            {
                                return true;
                            }
                            break;
                        case '*':
                            if (rawUrl.StartsWith(path, 0, path.Length - 1))
                            {
                                return true;
                            }
                            break;
                        default:
                            if (rawUrl.Equals(path))
                            {
                                return true;
                            }
                            break;
                    }
                }

            }
            return false;
        }
        public static bool IsLoginPath(SiteConfig config, String rawUrl)
        {
            return IsLoginPath(config, rawUrl, out var _);
        }
        public static void DeleteCache(String cacheKey)
        {
            File.Delete(cacheKey);
        }

        string Authority;
        public NetHttpRequest Reqesut(NetHttpRequest webr)
        {

            if (CheckPath("Redirect", String.Empty, out var replaceSetting))
            {
                var sb = new StringBuilder();
                var Referer = webr.Headers[HttpRequestHeader.Referer];
                if (String.IsNullOrEmpty(Referer) == false)
                {
                    ReplaceHost(replaceSetting, 0, Referer, sb, 0, 3, 3);

                    webr.Headers[HttpRequestHeader.Referer] = sb.ToString();

                }
                var Origin = webr.Headers["Origin"];
                if (String.IsNullOrEmpty(Origin) == false)
                {
                    sb.Clear();
                    ReplaceHost(replaceSetting, 0, Origin, sb, 0, 3, 3);
                    webr.Headers["Origin"] = sb.ToString();
                }
            }
            if (String.IsNullOrEmpty(this.Cookies) == false)
            {
                webr.Headers[HttpRequestHeader.Cookie] = this.Cookies;
            }
            WebServlet.WebHeaderConf(webr, this.Site, this.Context, this.SiteCookie.Account);

            webr.Timeout = (this.Site.Site.Timeout ?? 10) * 1000;
            return webr;
        }

        bool CheckPath(String path, String ctype, out SiteConfig.ReplaceSetting replaceSetting)
        {
            replaceSetting = null;
            if (String.IsNullOrEmpty(ctype))
            {
                foreach (var v in this.Site.HostPage)
                {

                    if (path.StartsWith(v.StartPath) == false)
                    {
                        continue;
                    }

                    if (path.EndsWith(v.EndPath) == false)
                    {
                        continue;
                    }
                    replaceSetting = v.Value;
                    return true;
                }
            }
            else
            {
                SiteConfig.ReplaceSetting typeSetting = null;

                foreach (var v in this.Site.HostPage)
                {
                    if (typeSetting == null)
                    {
                        if (String.IsNullOrEmpty(v.EndPath) && String.Equals(ctype, v.StartPath))
                        {
                            typeSetting = v.Value;
                            continue;
                        }
                    }

                    if (path.StartsWith(v.StartPath) == false)
                    {
                        continue;
                    }
                    if (path.EndsWith(v.EndPath) == false)
                    {
                        continue;
                    }
                    replaceSetting = v.Value;

                    return true;
                }

                replaceSetting = typeSetting;
            }
            return replaceSetting != null;
        }
        internal static bool CheckPath(String path, String ctype, out String key, String[] cfs)
        {

            if (CheckPath(path, out key, cfs) == false)
            {
                if (cfs.Contains(ctype))
                {
                    key = ctype;
                    return true;
                }
                return false;
            }
            return true;
        }
        internal static bool CheckPath(String path, out String key, String[] cfs)
        {

            key = null;
            foreach (String d in cfs)
            {
                int splitIndex = d.IndexOf('*');
                switch (splitIndex)
                {
                    case -1:
                        if (String.Equals(path, d, StringComparison.CurrentCultureIgnoreCase))
                        {
                            key = d;
                            return true;
                        }
                        break;
                    case 0:
                        if (path.EndsWith(d, 1))
                        {
                            key = d;
                            return true;
                        }
                        break;
                    default:
                        if (path.Length > splitIndex)
                        {
                            if (splitIndex == d.Length - 1)
                            {
                                if (path.StartsWith(d, 0, d.Length - 1))
                                {

                                    key = d;
                                    return true;
                                }
                            }
                            else if (path.StartsWith(d, 0, splitIndex) && path.EndsWith(d, splitIndex + 1))
                            {
                                key = d;
                                return true;
                            }
                        }
                        break;

                }
            }
            return false;
        }
        public string MD5(String src)
        {
            return MD5(src, this.Site.Site.Version);
        }
        public static string MD5(String src, String cap)
        {
            var md5 = System.Security.Cryptography.MD5.Create();
            byte[] md = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(src + cap));

            return UMC.Data.Utility.Parse36Encode(UMC.Data.Utility.IntParse(md));
        }
        public static long Int64MD5(String src)
        {
            var md5 = System.Security.Cryptography.MD5.Create();
            byte[] md = md5.ComputeHash(System.Text.Encoding.UTF8.GetBytes(src));

            var b = new byte[8];
            for (var i = 0; i < 8; i++)
            {
                b[i] = md[i * 2 + 1];
            }
            return BitConverter.ToInt64(b, 0);
        }


        void OutputAppendJS(Stream response, string encoding, String key, Stream output)
        {

            var mainKey = String.Format("SITE_JS_CONFIG_{0}{1}", this.Site.Root, key).ToUpper();
            var config = UMC.Data.DataFactory.Instance().Config(mainKey);

            if (config == null)
            {
                response.CopyTo(output);
                return;
            }
            var reader = new System.IO.StreamReader(DataFactory.Instance().Decompress(response, encoding));
            var writer = new System.IO.StreamWriter(output);

            int row = -1;
            var isEnd = false;
            if (config != null && String.IsNullOrEmpty(config.ConfValue) == false)
            {
                if (config.ConfValue.Trim().StartsWith(":"))
                {
                    var s = config.ConfValue.IndexOf('\n');
                    var su = config.ConfValue.Substring(0, s).Trim().Trim(':');
                    if (su.EndsWith("$"))
                    {
                        isEnd = true;
                    }
                    row = UMC.Data.Utility.IntParse(su.Trim('$'), -1);
                    config.ConfValue = config.ConfValue.Substring(s);
                }
            }
            var bf = new Char[1];
            var is_tr = false;
            int index = 1;
            if (row == 0)
            {
                is_tr = true;
                writer.WriteLine(config.ConfValue);
                if (isEnd)
                {
                    writer.Flush();
                    return;
                }
            }

            while (reader.ReadBlock(bf, 0, 1) > 0)
            {
                writer.Write(bf[0]);
                if (bf[0] == '\n')
                {
                    if (index == row)
                    {
                        is_tr = true;
                        writer.WriteLine(config.ConfValue);
                        if (isEnd)
                        {
                            break;
                        }
                    }
                    index++;
                }
            }
            if (is_tr == false)
            {
                writer.WriteLine(config.ConfValue);
            }

            writer.Flush();

        }
        void ReplaceHost(SiteConfig.ReplaceSetting replaceSetting, int start, String rawUrl, StringBuilder sb, int srcIndex, int destIndex, int decodeIndex)
        {
            var b = rawUrl[0];
            var isAppend = false;
            ReplaceHost((d, o, s) =>
            {
                while (o < s)
                {
                    sb.Append((char)d[o]);
                    o++;
                }
                if (isAppend)
                {
                    isAppend = false;
                    sb.Append(rawUrl[start - 1]);
                }

            }, (d, o, s) =>
            {
                if (start < rawUrl.Length)
                {
                    if (rawUrl[start] > 128)
                    {
                        d[o] = 0;
                        isAppend = true;
                        start++;
                        return 2;
                    }
                    else
                    {
                        d[o] = (byte)rawUrl[start];
                        start++;
                        return 1;
                    }
                }
                return 0;
            }, replaceSetting, srcIndex, destIndex, decodeIndex, String.Empty);
        }
        String ReplaceRawUrl(String rawUrl)
        {

            var searchIndex = rawUrl.IndexOf('?');

            if (searchIndex > 0)
            {

                if (this.CheckPath(rawUrl.Substring(0, searchIndex), String.Empty, out var replaceSetting))
                {
                    if ((replaceSetting.Model & SiteConfig.HostReplaceModel.Input) == SiteConfig.HostReplaceModel.Input)
                    {
                        var sb = new System.Text.StringBuilder();

                        sb.Append(rawUrl.Substring(0, searchIndex + 1));

                        ReplaceHost(replaceSetting, searchIndex + 1, rawUrl, sb, 0, 3, 3);
                        return sb.ToString();
                    }
                    else
                    {
                        return rawUrl;
                    }
                }
                else
                {
                    return rawUrl;
                }

            }
            return rawUrl;

        }

        void InputReplaceHost(System.IO.Stream writer, System.IO.Stream reader, SiteConfig.ReplaceSetting rpsetting)
        {
            ReplaceHost(writer.Write, reader.Read, rpsetting, 0, 2, 3, String.Empty);
        }
        #region Replacer

        static byte[] strHttps = UTF8Encoding.ASCII.GetBytes("https://");
        static byte[] strHttp = UTF8Encoding.ASCII.GetBytes("http://");
        static byte[] httpsEncode = UTF8Encoding.ASCII.GetBytes(Uri.EscapeDataString("https://"));
        static byte[] httpEncode = UTF8Encoding.ASCII.GetBytes(Uri.EscapeDataString("http://"));
        static byte[] strEncodePort = UTF8Encoding.ASCII.GetBytes("%3A");

        static byte[] HtmlHeadEnd = UTF8Encoding.ASCII.GetBytes("</head>");

        public class Replacer
        {
            byte[] nowScheme;
            byte[] nowSchemeEncode;//= httpEncode;
            NetWriteData _writer;
            SiteConfig.ReplaceSetting replaceSetting;
            int _srcIndex, _destIndex, _decodeIndex;
            string _headKey;
            HttpProxy _proxy;
            int _maxLength;
            int _minLength;
            byte[] buffer;

            bool isFind = false;
            bool isPort = false;
            bool isEncodePort = false;
            int bufferSize = 0;
            int bufferStart = 0;
            bool isHead;
            Func<bool> _check;
            public Replacer(HttpProxy proxy, NetWriteData writer, SiteConfig.ReplaceSetting setting, int srcIndex, int destIndex, int decodeIndex, string headKey)
            {
                this._proxy = proxy;
                this._writer = writer;
                this.replaceSetting = setting;
                this._decodeIndex = decodeIndex;
                this._destIndex = destIndex;
                this._srcIndex = srcIndex;
                if (String.IsNullOrEmpty(headKey) == false)
                {
                    _headKey = $"/UMC.Conf/{proxy.Site.Root}/{proxy.MD5(String.Empty)}/{MD5(headKey, String.Empty)}.js";
                    isHead = true;
                }
                var hLength = proxy.Site.MainHost.Hosts[srcIndex].Length;
                _minLength = proxy.Site.IsUnion ? Math.Min(hLength, proxy.Site.SuffixHost.Hosts[srcIndex].Length) : hLength;

                if (replaceSetting != null)
                {
                    _check = proxy.Site.IsUnion ? CheckUnionSetting : CheckSetting;
                    foreach (var hv in replaceSetting.Domains)
                    {
                        var item = hv.Hosts[srcIndex];
                        if (item.Length > hLength)
                        {
                            hLength = item.Length;
                        }
                        if (item.Length < _minLength)
                        {
                            _minLength = item.Length;
                        }
                    }
                }
                else
                {
                    _check = proxy.Site.IsUnion ? CheckUnion : Check;
                }


                if (proxy.Context.Url.Scheme.Length > 4)
                {
                    this.nowScheme = strHttps;
                    this.nowSchemeEncode = httpsEncode;
                }
                else
                {
                    this.nowScheme = strHttp;
                    this.nowSchemeEncode = httpEncode;

                }
                this._maxLength = 14 + hLength;

                this.buffer = new byte[_maxLength];
            }
            int Read(NetReadData reader)
            {
                if (bufferSize == _maxLength)
                {
                    _writer(buffer, 0, 1);
                    Array.Copy(buffer, 1, buffer, 0, bufferSize - 1);
                    bufferSize--;
                    if (bufferStart > 0)
                    {
                        bufferStart--;
                    }
                }
                return reader(buffer, bufferSize, 1);
            }
            public void Replace(NetReadData reader)
            {
                byte value;
                int len = 0;
                while ((len = Read(reader)) > 0)
                {
                    value = buffer[bufferSize];
                    bufferSize++;
                    switch (value)
                    {
                        case 0:
                            if (len > 1)
                                bufferSize--;
                            goto case 20;
                        case 20:
                        default:
                            bufferStart = 0;
                            isEncodePort = false;
                            isPort = false;
                            _writer(buffer, 0, bufferSize);
                            bufferSize = 0;
                            isFind = false;
                            continue;
                        case 60://<
                            if (isHead)
                            {
                                continue;
                            }
                            else
                            {
                                goto case 20;
                            }
                        case 62://>
                            if (isHead && EndsWith(buffer, bufferSize, HtmlHeadEnd))
                            {
                                isHead = false;
                                bufferSize = bufferSize - HtmlHeadEnd.Length;
                                _writer(buffer, 0, bufferSize);
                                var bData = UTF8Encoding.ASCII.GetBytes($"<script src=\"{_headKey}\"></script>\r\n</head>");
                                _writer(bData, 0, bData.Length);
                                bufferSize = 0;
                                bufferStart = 0;
                                continue;

                            }
                            goto case 20;
                        case 58://':':
                            if (isFind)
                            {
                                isFind = false;
                                isPort = true;
                                bufferSize--;
                                continue;
                            }
                            else
                            {
                                bufferStart = bufferSize;
                                goto case 100;
                            }

                        case 37://'%':
                            if (isFind)
                            {
                                isPort = false;
                                isFind = false;
                                isEncodePort = true;
                                continue;
                            }
                            else
                            {
                                bufferStart = bufferSize;
                                goto case 100;
                            }
                        case 48://0
                        case 49://1
                        case 50://2
                        case 51://3
                        case 52://4
                        case 53://5
                        case 54://6
                        case 55://7
                        case 56://8
                        case 57://9
                            if (isPort)
                            {
                                bufferSize--;
                                continue;
                            }
                            goto case 100;
                        case 65://A
                        case 70: //F
                            bufferStart = bufferSize;
                            goto case 100;
                        case 47://“/”
                            bufferStart = bufferSize;
                            goto case 100;

                        case 45://-
                        case 46://.
                                // case 47://“/”
                        case 97://a
                        case 98://b
                        case 99://c
                        case 100://d
                        case 101://e
                        case 102://f
                        case 103://g
                        case 104://h
                        case 105://i
                        case 106://j
                        case 107://k
                        case 108://l
                        case 109://m
                        case 110://n
                        case 111://o
                        case 112://p
                        case 113://q
                        case 114://r
                        case 115://s
                        case 116://t
                        case 117://u
                        case 118://v
                        case 119://w
                        case 120://x
                        case 121://y
                        case 122://z
                            if (isEncodePort && bufferSize == 3)
                            {
                                isEncodePort = false;
                                if (EndsWith(buffer, bufferSize, strEncodePort))
                                {
                                    isPort = true;
                                    bufferSize = 0;
                                    bufferStart = 0;
                                }
                                continue;
                            }
                            isPort = false;

                            len = bufferSize - bufferStart;

                            if (_minLength > len)
                            {
                                continue;
                            }
                            break;

                    }
                    isFind = _check();

                }

            }
            bool CheckUnion()
            {
                if (EndWith(this._proxy.Site.MainHost) == false)
                {
                    return EndWith(this._proxy.Site.SuffixHost);
                }
                return true;
            }
            bool Check()
            {
                return EndWith(this._proxy.Site.MainHost);
            }
            bool CheckSetting()
            {
                foreach (var hem in replaceSetting.Domains)
                {
                    if (EndWith(hem))
                    {
                        return true;
                    }
                }
                return EndWith(this._proxy.Site.MainHost);

            }
            bool CheckUnionSetting()
            {
                foreach (var hem in replaceSetting.Domains)
                {
                    if (EndWith(hem))
                    {
                        return true;
                    }
                }
                if (EndWith(this._proxy.Site.MainHost) == false)
                {
                    return EndWith(this._proxy.Site.SuffixHost);
                }
                return true;

            }
            bool EndWith(SiteConfig.HostConvert hem)
            {
                var khost = hem.Hosts[_srcIndex];
                if (EndsWith(buffer, bufferStart, bufferSize - bufferStart, khost))
                {
                    bufferStart = 0;

                    bufferSize = bufferSize - khost.Length;
                    if (EndsWith(buffer, bufferSize, strHttps))
                    {
                        bufferSize = bufferSize - strHttps.Length;
                        _writer(buffer, 0, bufferSize);
                        _writer(nowScheme, 0, nowScheme.Length);
                        _writer(hem.Hosts[_destIndex], 0, hem.Hosts[_destIndex].Length);
                    }
                    else if (EndsWith(buffer, bufferSize, strHttp))
                    {
                        bufferSize = bufferSize - strHttp.Length;
                        _writer(buffer, 0, bufferSize);
                        _writer(nowScheme, 0, nowScheme.Length);
                        _writer(hem.Hosts[_destIndex], 0, hem.Hosts[_destIndex].Length);
                    }
                    else if (EndsWith(buffer, bufferSize, httpsEncode))
                    {
                        // isEncode = true;
                        bufferSize = bufferSize - httpsEncode.Length;
                        _writer(buffer, 0, bufferSize);
                        _writer(nowSchemeEncode, 0, nowSchemeEncode.Length);
                        _writer(hem.Hosts[_decodeIndex], 0, hem.Hosts[_decodeIndex].Length);
                    }
                    else if (EndsWith(buffer, bufferSize, httpEncode))
                    {
                        // isEncode = true;
                        bufferSize = bufferSize - httpEncode.Length;
                        _writer(buffer, 0, bufferSize);
                        _writer(nowSchemeEncode, 0, nowSchemeEncode.Length);
                        _writer(hem.Hosts[_decodeIndex], 0, hem.Hosts[_decodeIndex].Length);
                    }
                    else
                    {
                        _writer(buffer, 0, bufferSize);
                        _writer(hem.Hosts[_destIndex], 0, hem.Hosts[_destIndex].Length);
                    }
                    bufferSize = 0;
                    return true;
                }
                return false;
            }
            public void Flush()
            {
                if (bufferSize > 0)
                {
                    _writer(buffer, 0, bufferSize);
                }
            }

        }
        #endregion
        void ReplaceHost(NetWriteData writer, NetReadData reader, SiteConfig.ReplaceSetting replaceSetting, int srcIndex, int destIndex, int decodeIndex, string headKey)
        {
            var replacer = new Replacer(this, writer, replaceSetting, srcIndex, destIndex, decodeIndex, headKey);
            replacer.Replace(reader);
            replacer.Flush();

        }
        String ReplaceRedirect(String redirect)
        {

            SiteConfig.ReplaceSetting rpsetting;

            CheckPath("Redirect", String.Empty, out rpsetting);

            var sb = new StringBuilder();
            OutputReplace(sb, redirect, rpsetting);//, 0, redirect, sb, 1, 0, 0);
            return sb.ToString();
        }
        // return redirect;

        void OutputReplace(StringBuilder sb, String cookie, SiteConfig.ReplaceSetting rpsetting)
        {
            ReplaceHost(rpsetting, 0, cookie, sb, 1, 0, 0);
        }

        void OuterEncoding(Stream response, string encoding, Stream output, bool isEncoding)
        {
            if (isEncoding)
            {
                if (String.IsNullOrEmpty(encoding) == false)
                {
                    this.Context.AddHeader("Content-Encoding", encoding);
                    response.CopyTo(output);
                }
                else
                {
                    this.Context.AddHeader("Content-Encoding", "deflate");
                    var deflate2 =
                             new DeflateStream(output, CompressionMode.Compress);
                    response.CopyTo(deflate2);
                    deflate2.Flush();

                }
            }
            else
            {
                DataFactory.Instance().Decompress(response, encoding).CopyTo(output);
            }
        }
        void OuterReplaceHost(Stream response, string encoding, SiteConfig.ReplaceSetting rpsetting, Stream output, bool isEncoding)
        {
            if (rpsetting == null)
            {
                OuterEncoding(response, encoding, output, isEncoding);

                return;
            }
            var rp = rpsetting.Model;

            if ((rp & SiteConfig.HostReplaceModel.Replace) != SiteConfig.HostReplaceModel.Replace)
            {
                OuterEncoding(response, encoding, output, isEncoding);
                return;
            }

            Stream stream;
            if (isEncoding)
            {
                stream = new DeflateStream(output, CompressionMode.Compress);

                this.Context.AddHeader("Content-Encoding", "deflate");
            }
            else
            {
                stream = output;
            }

            var reader = DataFactory.Instance().Decompress(response, encoding);

            ReplaceHost(stream.Write, reader.Read, rpsetting, 1, 0, 0, String.Empty);
            stream.Flush();
        }

        void OuterHTML(Stream response, SiteConfig.ReplaceSetting replaceSetting, string encoding, Stream output, bool isEncoding, string jsKey)
        {


            if (String.IsNullOrEmpty(jsKey) && replaceSetting?.Model == SiteConfig.HostReplaceModel.Input)
            {

                OuterEncoding(response, encoding, output, isEncoding);

                return;
            }

            Stream stream;
            if (isEncoding)
            {

                stream = new DeflateStream(output, CompressionMode.Compress);

                this.Context.AddHeader("Content-Encoding", "deflate");

            }
            else
            {
                stream = output;
            }

            ReplaceHost(stream.Write, DataFactory.Instance().Decompress(response, encoding).Read, replaceSetting, 1, 0, 0, jsKey);

            stream.Flush();
        }
        static bool EndsWith(byte[] buffer, int bl, Span<byte> end)
        {
            return EndsWith(buffer, 0, bl, end);
        }
        static bool EndsWith(byte[] buffer, int offset, int size, Span<byte> end)
        {
            var el = end.Length;
            if (el <= size)
            {
                offset = offset + size - el;
                for (var i = 0; i < el; i++)
                {
                    if (end[i] != buffer[offset + i])
                    {
                        return false;
                    }
                }
                return true;
            }
            return false;
        }
        public static bool TryImageConf(string confKey, out WebMeta confValue)
        {
            confValue = null;
            if (String.IsNullOrEmpty(confKey) == false)
            {

                var match = System.Text.RegularExpressions.Regex.Match(confKey, "^[h|w|c|t|m|b](\\d+)([-|x]\\d+)?([g|p|j|w|a|o]?)$");

                if (match.Success)
                {
                    confValue = new WebMeta();
                    switch (match.Groups[3].Value)
                    {
                        case "g":
                            confValue.Put("Format", "gif");
                            break;
                        case "j":
                            confValue.Put("Format", "jpeg");
                            break;
                        case "w":
                            confValue.Put("Format", "webp");
                            break;
                        case "p":
                            confValue.Put("Format", "png");
                            break;
                        case "a":
                            confValue.Put("Format", "avif");
                            break;
                        case "o":
                            confValue.Put("Format", "Optimal");
                            break;

                    }
                    confValue.Put("Width", match.Groups[1].Value);
                    if (match.Groups[2].Length > 0)
                    {
                        switch (match.Groups[0].Value[0])
                        {
                            case '-':
                                confValue.Put("Width", "-" + match.Groups[1].Value);
                                confValue.Put("Height", "-" + match.Groups[0].Value);
                                break;
                            default:
                                confValue.Put("Height", match.Groups[2].Value.Substring(1));
                                break;
                        }
                    }
                    else
                    {

                        confValue.Put("Height", match.Groups[1].Value);
                    }
                    switch (confKey[0])
                    {
                        case 'w':
                            confValue.Remove("Height");
                            break;
                        case 'h':
                            confValue.Remove("Width");
                            break;
                        case 'c':
                            confValue["Model"] = "0";
                            break;
                        case 't':
                            confValue["Model"] = "1";
                            break;
                        case 'm':
                            confValue["Model"] = "2";
                            break;
                        case 'b':
                            confValue["Model"] = "3";
                            break;
                    }
                    return true;
                }
                else
                {
                    switch (confKey)
                    {
                        case "g":
                            confValue = new WebMeta().Put("Format", "gif");
                            return true;
                        case "j":
                            confValue = new WebMeta().Put("Format", "jpeg");
                            return true;
                        case "w":
                            confValue = new WebMeta().Put("Format", "webp");
                            return true;
                        case "p":
                            confValue = new WebMeta().Put("Format", "png");
                            return true;

                    }
                }
            }
            return false;

        }

        public static bool TryImageConfig(string rook, string confKey, out WebMeta confValue)
        {
            confValue = null;
            if (String.IsNullOrEmpty(confKey) == false)
            {

                if (TryImageConf(confKey, out confValue))
                {
                    return true;
                }
                var mainKey = String.Format("SITE_IMAGE_CONFIG_{0}{1}", rook, MD5(confKey, "")).ToUpper();
                var config = UMC.Data.DataFactory.Instance().Config(mainKey);
                if (config != null)
                {
                    confValue = UMC.Data.JSON.Deserialize<WebMeta>(config.ConfValue);
                    if (confValue != null)
                    {
                        return true;
                    }
                }
            }
            return false;

        }
    }
}
